diff options
Diffstat (limited to 'myisam')
38 files changed, 822 insertions, 372 deletions
diff --git a/myisam/Makefile.am b/myisam/Makefile.am index 0b8a25e3404..c61647b25f7 100644 --- a/myisam/Makefile.am +++ b/myisam/Makefile.am @@ -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$(top_srcdir)/include +INCLUDES = -I$(top_srcdir)/include LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ $(top_builddir)/mysys/libmysys.a \ $(top_builddir)/dbug/libdbug.a \ diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 62c68322595..530f0d56c4c 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -68,7 +68,7 @@ struct st_ftb_expr my_off_t docid[2]; float weight; float cur_weight; - byte *quot, *qend; + LIST *phrase; /* phrase words */ uint yesses; /* number of "yes" words matched */ uint nos; /* number of "no" words matched */ uint ythresh; /* number of "yes" words in expr */ @@ -132,20 +132,22 @@ static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b) } static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, - FTB_EXPR *up, uint depth) + FTB_EXPR *up, uint depth, byte *up_quot) { byte res; FTB_PARAM param; FT_WORD w; FTB_WORD *ftbw; FTB_EXPR *ftbe; + FT_WORD *phrase_word; + LIST *phrase_list; uint extra=HA_FT_WLEN+ftb->info->s->rec_reflength; /* just a shortcut */ if (ftb->state != UNINITIALIZED) return; param.prev=' '; - param.quot=up->quot; + param.quot= up_quot; while ((res=ft_get_word(ftb->charset,start,end,&w,¶m))) { int r=param.plusminus; @@ -172,6 +174,14 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, if (param.yesno > 0) up->ythresh++; queue_insert(& ftb->queue, (byte *)ftbw); ftb->with_scan|=(param.trunc & FTB_FLAG_TRUNC); + case 4: /* not indexed word (stopword or too short/long) */ + if (! up_quot) break; + phrase_word= (FT_WORD *)alloc_root(&ftb->mem_root, sizeof(FT_WORD)); + phrase_list= (LIST *)alloc_root(&ftb->mem_root, sizeof(LIST)); + phrase_word->pos= w.pos; + phrase_word->len= w.len; + phrase_list->data= (void *)phrase_word; + up->phrase= list_add(up->phrase, phrase_list); break; case 2: /* left bracket */ ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR)); @@ -182,13 +192,14 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, ftbe->up=up; ftbe->ythresh=ftbe->yweaks=0; ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR; - if ((ftbe->quot=param.quot)) ftb->with_scan|=2; + ftbe->phrase= NULL; + if (param.quot) ftb->with_scan|=2; if (param.yesno > 0) up->ythresh++; - _ftb_parse_query(ftb, start, end, ftbe, depth+1); + _ftb_parse_query(ftb, start, end, ftbe, depth+1, param.quot); param.quot=0; break; case 3: /* right bracket */ - if (up->quot) up->qend=param.quot; + if (up_quot) up->phrase= list_reverse(up->phrase); return; } } @@ -211,6 +222,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength; byte *lastkey_buf=ftbw->word+ftbw->off; + LINT_INIT(off); if (ftbw->flags & FTB_FLAG_TRUNC) lastkey_buf+=ftbw->len; @@ -409,12 +421,12 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftbe->weight=1; ftbe->flags=FTB_FLAG_YES; ftbe->nos=1; - ftbe->quot=0; ftbe->up=0; ftbe->ythresh=ftbe->yweaks=0; ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR; + ftbe->phrase= NULL; ftb->root=ftbe; - _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0); + _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0, NULL); ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root, sizeof(FTB_WORD *)*ftb->queue.elements); memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements); @@ -430,29 +442,45 @@ err: } -/* returns 1 if str0 ~= /\bstr1\b/ */ -static int _ftb_strstr(const byte *s0, const byte *e0, - const byte *s1, const byte *e1, - CHARSET_INFO *cs) +/* + Checks if given buffer matches phrase list. + + SYNOPSIS + _ftb_check_phrase() + s0 start of buffer + e0 end of buffer + phrase broken into list phrase + cs charset info + + RETURN VALUE + 1 is returned if phrase found, 0 else. +*/ + +static int _ftb_check_phrase(const byte *s0, const byte *e0, + LIST *phrase, CHARSET_INFO *cs) { - const byte *p0= s0; - my_bool s_after= true_word_char(cs, s1[0]); - my_bool e_before= true_word_char(cs, e1[-1]); - uint p0_len; - my_match_t m[2]; + FT_WORD h_word; + const byte *h_start= s0; + DBUG_ENTER("_ftb_strstr"); + DBUG_ASSERT(phrase); - while (p0 < e0) + while (ft_simple_get_word(cs, (byte **)&h_start, e0, &h_word, FALSE)) { - if (cs->coll->instr(cs, p0, e0 - p0, s1, e1 - s1, m, 2) != 2) - return(0); - if ((!s_after || p0 + m[1].beg == s0 || !true_word_char(cs, p0[m[1].beg-1])) && - (!e_before || p0 + m[1].end == e0 || !true_word_char(cs, p0[m[1].end]))) - return(1); - p0+= m[1].beg; - p0+= (p0_len= my_mbcharlen(cs, *(uchar *)p0)) ? p0_len : 1; + FT_WORD *n_word; + LIST *phrase_element= phrase; + const byte *h_start1= h_start; + for (;;) + { + n_word= (FT_WORD *)phrase_element->data; + if (my_strnncoll(cs, h_word.pos, h_word.len, n_word->pos, n_word->len)) + break; + if (! (phrase_element= phrase_element->next)) + DBUG_RETURN(1); + if (! ft_simple_get_word(cs, (byte **)&h_start1, e0, &h_word, FALSE)) + DBUG_RETURN(0); + } } - - return(0); + DBUG_RETURN(0); } @@ -483,7 +511,7 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_ { yn=ftbe->flags; weight=ftbe->cur_weight*ftbe->weight; - if (mode && ftbe->quot) + if (mode && ftbe->phrase) { int not_found=1; @@ -492,8 +520,8 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_ { if (!ftsi.pos) continue; - not_found = ! _ftb_strstr(ftsi.pos, ftsi.pos+ftsi.len, - ftbe->quot, ftbe->qend, ftb->charset); + not_found = ! _ftb_check_phrase(ftsi.pos, ftsi.pos+ftsi.len, + ftbe->phrase, ftb->charset); } if (not_found) break; } /* ftbe->quot */ @@ -641,8 +669,8 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) continue; end=ftsi.pos+ftsi.len; - while (ft_simple_get_word(ftb->charset, - (byte **) &ftsi.pos, (byte *) end, &word)) + while (ft_simple_get_word(ftb->charset, (byte **) &ftsi.pos, + (byte *) end, &word, TRUE)) { int a, b, c; for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2) diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 0b1e68b0d70..2fad2363ae2 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -93,12 +93,14 @@ my_bool ft_boolean_check_syntax_string(const byte *str) return 0; } -/* returns: - * 0 - eof - * 1 - word found - * 2 - left bracket - * 3 - right bracket - */ +/* + RETURN VALUE + 0 - eof + 1 - word found + 2 - left bracket + 3 - right bracket + 4 - stopword found +*/ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) { @@ -161,6 +163,11 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, *start=doc; return 1; } + else if (length) /* make sure length > 0 (if start contains spaces only) */ + { + *start= doc; + return 4; + } } if (param->quot) { @@ -170,18 +177,19 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, return 0; } -byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end, - FT_WORD *word) +byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, const byte *end, + FT_WORD *word, my_bool skip_stopwords) { byte *doc= *start; uint mwc, length, mbl; DBUG_ENTER("ft_simple_get_word"); - while (doc<end) + do { - for (;doc<end;doc++) + for (;; doc++) { - if (true_word_char(cs,*doc)) break; + if (doc >= end) DBUG_RETURN(0); + if (true_word_char(cs, *doc)) break; } mwc= length= 0; @@ -193,13 +201,14 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end, word->len= (uint)(doc-word->pos) - mwc; - if (length >= ft_min_word_len && length < ft_max_word_len && - !is_stopword(word->pos, word->len)) + if (skip_stopwords == FALSE || + (length >= ft_min_word_len && length < ft_max_word_len && + !is_stopword(word->pos, word->len))) { *start= doc; DBUG_RETURN(1); } - } + } while (doc < end); DBUG_RETURN(0); } @@ -217,7 +226,7 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc) FT_WORD w; DBUG_ENTER("ft_parse"); - while (ft_simple_get_word(wtree->custom_arg, &doc,end,&w)) + while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE)) { if (with_alloc) { diff --git a/myisam/ft_static.c b/myisam/ft_static.c index 994a94d0c49..e221950f445 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -25,23 +25,25 @@ char ft_boolean_syntax[]="+ -><()~*:\"\"&|"; const HA_KEYSEG ft_keysegs[FT_SEGS]={ { - HA_KEYTYPE_VARTEXT, /* type */ - 63, /* language (will be overwritten) */ - 0, 0, 0, /* null_bit, bit_start, bit_end */ - HA_VAR_LENGTH | HA_PACK_KEY, /* flag */ - HA_FT_MAXBYTELEN, /* length */ - HA_FT_WLEN, /* start */ - 0, /* null_pos */ - NULL /* charset */ - }, - { -/* - Note, this (and the last HA_KEYTYPE_END) segment should NOT - be packed in any way, otherwise w_search() won't be able to - update key entry 'in vivo' -*/ - HA_FT_WTYPE, 63, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 0, 0, NULL - } + 0, /* charset */ + HA_FT_WLEN, /* start */ + 0, /* null_pos */ + 0, /* Bit pos */ + HA_VAR_LENGTH_PART | HA_PACK_KEY, /* flag */ + HA_FT_MAXBYTELEN, /* length */ + HA_KEYTYPE_VARTEXT2, /* type */ + 63, /* language (will be overwritten) */ + 0, /* null_bit */ + 2, 0, 0 /* bit_start, bit_end, bit_length */ +}, +{ + /* + Note, this (and the last HA_KEYTYPE_END) segment should NOT + be packed in any way, otherwise w_search() won't be able to + update key entry 'in vivo' + */ + 0, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, HA_FT_WTYPE, 63, 0, 0, 0, 0 +} }; const struct _ft_vft _ft_vft_nlq = { diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c index a4bce6ad4e8..ab51afb0e82 100644 --- a/myisam/ft_stopwords.c +++ b/myisam/ft_stopwords.c @@ -81,7 +81,7 @@ int ft_init_stopwords() goto err0; len=my_read(fd, buffer, len, MYF(MY_WME)); end=start+len; - while (ft_simple_get_word(default_charset_info, &start, end, &w)) + while (ft_simple_get_word(default_charset_info, &start, end, &w, TRUE)) { if (ft_add_stopword(my_strdup_with_length(w.pos, w.len, MYF(0)))) goto err1; diff --git a/myisam/ft_test1.c b/myisam/ft_test1.c index f4884f8ca39..14be9aa1e8c 100644 --- a/myisam/ft_test1.c +++ b/myisam/ft_test1.c @@ -79,24 +79,24 @@ static int run_test(const char *filename) recinfo[0].length= (extra_field == FIELD_BLOB ? 4 + mi_portable_sizeof_char_ptr : extra_length); if (extra_field == FIELD_VARCHAR) - recinfo[0].length+=2; + recinfo[0].length+= HA_VARCHAR_PACKLENGTH(extra_length); recinfo[1].type=key_field; recinfo[1].length= (key_field == FIELD_BLOB ? 4+mi_portable_sizeof_char_ptr : key_length); if (key_field == FIELD_VARCHAR) - recinfo[1].length+=2; + recinfo[1].length+= HA_VARCHAR_PACKLENGTH(key_length); /* Define a key over the first column */ keyinfo[0].seg=keyseg; keyinfo[0].keysegs=1; keyinfo[0].seg[0].type= key_type; - keyinfo[0].seg[0].flag= (key_field == FIELD_BLOB)?HA_BLOB_PART: - (key_field == FIELD_VARCHAR)?HA_VAR_LENGTH:0; + keyinfo[0].seg[0].flag= (key_field == FIELD_BLOB) ? HA_BLOB_PART: + (key_field == FIELD_VARCHAR) ? HA_VAR_LENGTH_PART:0; keyinfo[0].seg[0].start=recinfo[0].length; keyinfo[0].seg[0].length=key_length; keyinfo[0].seg[0].null_bit= 0; keyinfo[0].seg[0].null_pos=0; - keyinfo[0].seg[0].language=MY_CHARSET_CURRENT; + keyinfo[0].seg[0].language= default_charset_info->number; keyinfo[0].flag = (no_fulltext?HA_PACK_KEY:HA_FULLTEXT); if (!silent) @@ -155,33 +155,42 @@ static int run_test(const char *filename) if (!silent) printf("- Reading rows with key\n"); for (i=0 ; i < NQUERIES ; i++) - { FT_DOCLIST *result; + { + FT_DOCLIST *result; result=ft_nlq_init_search(file,0,(char*) query[i],strlen(query[i]),1); - if(!result) { + if(!result) + { printf("Query %d: `%s' failed with errno %3d\n",i,query[i],my_errno); continue; } printf("Query %d: `%s'. Found: %d. Top five documents:\n", - i,query[i],result->ndocs); - for(j=0;j<5;j++) { double w; int err; - err=ft_nlq_read_next(result, read_record); - if(err==HA_ERR_END_OF_FILE) { - printf("No more matches!\n"); - break; - } else if (err) { - printf("ft_read_next %d failed with errno %3d\n",j,my_errno); - break; - } - w=ft_nlq_get_relevance(result); - if(key_field == FIELD_VARCHAR) { - uint l; - char *p; - p=recinfo[0].length+read_record; - l=uint2korr(p); - printf("%10.7f: %.*s\n",w,(int) l,p+2); - } else - printf("%10.7f: %.*s\n",w,recinfo[1].length, - recinfo[0].length+read_record); + i,query[i],result->ndocs); + for (j=0;j<5;j++) + { + double w; int err; + err= ft_nlq_read_next(result, read_record); + if (err==HA_ERR_END_OF_FILE) + { + printf("No more matches!\n"); + break; + } + else if (err) + { + printf("ft_read_next %d failed with errno %3d\n",j,my_errno); + break; + } + w=ft_nlq_get_relevance(result); + if (key_field == FIELD_VARCHAR) + { + uint l; + char *p; + p=recinfo[0].length+read_record; + l=uint2korr(p); + printf("%10.7f: %.*s\n",w,(int) l,p+2); + } + else + printf("%10.7f: %.*s\n",w,recinfo[1].length, + recinfo[0].length+read_record); } ft_nlq_close_search(result); } @@ -215,9 +224,14 @@ void create_record(char *pos, int n) else if (recinfo[0].type == FIELD_VARCHAR) { uint tmp; - strnmov(pos+2,data[n].f0,keyinfo[0].seg[0].length); - tmp=strlen(pos+2); - int2store(pos,tmp); + /* -1 is here because pack_length is stored in seg->length */ + uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1); + strnmov(pos+pack_length,data[n].f0,keyinfo[0].seg[0].length); + tmp=strlen(pos+pack_length); + if (pack_length == 1) + *pos= (char) tmp; + else + int2store(pos,tmp); pos+=recinfo[0].length; } else @@ -239,9 +253,14 @@ void create_record(char *pos, int n) else if (recinfo[1].type == FIELD_VARCHAR) { uint tmp; - strnmov(pos+2,data[n].f2,keyinfo[0].seg[0].length); - tmp=strlen(pos+2); - int2store(pos,tmp); + /* -1 is here because pack_length is stored in seg->length */ + uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1); + strnmov(pos+pack_length,data[n].f2,keyinfo[0].seg[0].length); + tmp=strlen(pos+1); + if (pack_length == 1) + *pos= (char) tmp; + else + int2store(pos,tmp); pos+=recinfo[1].length; } else diff --git a/myisam/ft_update.c b/myisam/ft_update.c index beccc062270..b8cd925bf4f 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -58,29 +58,27 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi) DBUG_ENTER("_mi_ft_segiterator"); if (!ftsi->num) - { DBUG_RETURN(0); - } - else - ftsi->num--; + + ftsi->num--; if (!ftsi->seg) - { DBUG_RETURN(1); - } - else - ftsi->seg--; + + ftsi->seg--; if (ftsi->seg->null_bit && (ftsi->rec[ftsi->seg->null_pos] & ftsi->seg->null_bit)) { - ftsi->pos=0; - DBUG_RETURN(1); + ftsi->pos=0; + DBUG_RETURN(1); } ftsi->pos= ftsi->rec+ftsi->seg->start; - if (ftsi->seg->flag & HA_VAR_LENGTH) + if (ftsi->seg->flag & HA_VAR_LENGTH_PART) { - ftsi->len=uint2korr(ftsi->pos); - ftsi->pos+=2; /* Skip VARCHAR length */ + uint pack_length= (ftsi->seg->bit_start); + ftsi->len= (pack_length == 1 ? (uint) *(uchar*) ftsi->pos : + uint2korr(ftsi->pos)); + ftsi->pos+= pack_length; /* Skip VARCHAR length */ DBUG_RETURN(1); } if (ftsi->seg->flag & HA_BLOB_PART) @@ -296,9 +294,11 @@ uint _ft_make_key(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wptr, DBUG_RETURN(_mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos)); } + /* convert key value to ft2 */ + uint _mi_ft_convert_to_ft2(MI_INFO *info, uint keynr, uchar *key) { my_off_t root; @@ -316,9 +316,12 @@ uint _mi_ft_convert_to_ft2(MI_INFO *info, uint keynr, uchar *key) get_key_full_length_rdonly(key_length, key); while (_mi_ck_delete(info, keynr, key, key_length) == 0) - /* nothing to do here. - _mi_ck_delete() will populate info->ft1_to_ft2 with deleted keys - */; + { + /* + nothing to do here. + _mi_ck_delete() will populate info->ft1_to_ft2 with deleted keys + */ + } /* creating pageful of keys */ mi_putint(info->buff,length+2,0); diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index ddb9fbfead2..91c679a1e58 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -112,7 +112,8 @@ int is_stopword(char *word, uint len); uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t); byte ft_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *, FTB_PARAM *); -byte ft_simple_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *); +byte ft_simple_get_word(CHARSET_INFO *, byte **, const byte *, + FT_WORD *, my_bool); typedef struct _st_ft_seg_iterator { uint num, len; diff --git a/myisam/mi_check.c b/myisam/mi_check.c index d59c9b9c697..38f3ebaa20a 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -281,7 +281,8 @@ int chk_size(MI_CHECK *param, register MI_INFO *info) size=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0)); if ((skr=(my_off_t) info->state->key_file_length) != size) { - if (skr > size) + /* Don't give error if file generated by myisampack */ + if (skr > size && info->s->state.key_map) { error=1; mi_check_print_error(param, @@ -2043,7 +2044,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, sort_param.key_length+=keyseg[i].length; if (keyseg[i].flag & HA_SPACE_PACK) sort_param.key_length+=get_pack_length(keyseg[i].length); - if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH)) + if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART)) sort_param.key_length+=2 + test(keyseg[i].length >= 127); if (keyseg[i].flag & HA_NULL_PART) sort_param.key_length++; @@ -2452,7 +2453,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, sort_param[i].key_length+=keyseg->length; if (keyseg->flag & HA_SPACE_PACK) sort_param[i].key_length+=get_pack_length(keyseg->length); - if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH)) + if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART)) sort_param[i].key_length+=2 + test(keyseg->length >= 127); if (keyseg->flag & HA_NULL_PART) sort_param[i].key_length++; diff --git a/myisam/mi_checksum.c b/myisam/mi_checksum.c index 95338434211..33a51068fb0 100644 --- a/myisam/mi_checksum.c +++ b/myisam/mi_checksum.c @@ -40,8 +40,12 @@ ha_checksum mi_checksum(MI_INFO *info, const byte *buf) } case FIELD_VARCHAR: { - length=uint2korr(buf); - pos=buf+2; + uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length-1); + if (pack_length == 1) + length= (ulong) *(uchar*) buf; + else + length= uint2korr(buf); + pos= buf+pack_length; break; } default: diff --git a/myisam/mi_create.c b/myisam/mi_create.c index d363f3d5b67..12b03e65baa 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -43,7 +43,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, myf create_flag; uint fields,length,max_key_length,packed,pointer,real_length_diff, key_length,info_length,key_segs,options,min_key_length_skip, - base_pos,varchar_count,long_varchar_count,varchar_length, + base_pos,long_varchar_count,varchar_length, max_key_block_length,unique_key_parts,fulltext_keys,offset; ulong reclength, real_reclength,min_pack_length; char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; @@ -99,7 +99,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* Start by checking fields and field-types used */ - reclength=varchar_count=varchar_length=long_varchar_count=packed= + reclength=varchar_length=long_varchar_count=packed= min_pack_length=pack_reclength=0; for (rec=recinfo, fields=0 ; fields != columns ; @@ -130,14 +130,15 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, } else if (type == FIELD_VARCHAR) { - varchar_count++; - varchar_length+=rec->length-2; + varchar_length+= rec->length-1; /* Used for min_pack_length */ packed--; - pack_reclength+=1; - if (test(rec->length > 257)) - { /* May be packed on 3 bytes */ + pack_reclength++; + min_pack_length++; + /* We must test for 257 as length includes pack-length */ + if (test(rec->length >= 257)) + { long_varchar_count++; - pack_reclength+=2; + pack_reclength+= 2; /* May be packed on 3 bytes */ } } else if (type != FIELD_SKIP_ZERO) @@ -169,12 +170,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* 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 - { - min_pack_length+=varchar_length+2*varchar_count; - } + if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))) + min_pack_length+= varchar_length; if (flags & HA_CREATE_TMP_TABLE) { options|= HA_OPTION_TMP_TABLE; @@ -194,11 +191,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_PACK_RECORD)); min_pack_length+=packed; - if (!ci->data_file_length) + if (!ci->data_file_length && ci->max_rows) { - if (ci->max_rows == 0 || pack_reclength == INT_MAX32) - ci->data_file_length= INT_MAX32-1; /* Should be enough */ - else if ((~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength) + if (pack_reclength == INT_MAX32 || + (~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength) ci->data_file_length= ~(ulonglong) 0; else ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength; @@ -223,7 +219,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, reclength=pointer+1; /* reserve place for delete link */ } else - reclength+=long_varchar_count; /* We need space for this! */ + reclength+= long_varchar_count; /* We need space for varchar! */ max_key_length=0; tot_length=0 ; key_segs=0; fulltext_keys=0; @@ -264,7 +260,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, j++, keyseg++) { if (keyseg->type != HA_KEYTYPE_BINARY && - keyseg->type != HA_KEYTYPE_VARBINARY) + keyseg->type != HA_KEYTYPE_VARBINARY1 && + keyseg->type != HA_KEYTYPE_VARBINARY2) { my_errno=HA_WRONG_CREATE_OPTION; goto err; @@ -279,8 +276,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, goto err; #endif /*HAVE_SPATIAL*/ } - else - if (keydef->flag & HA_FULLTEXT) + else if (keydef->flag & HA_FULLTEXT) { keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY; options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ @@ -289,11 +285,22 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, j++, keyseg++) { if (keyseg->type != HA_KEYTYPE_TEXT && - keyseg->type != HA_KEYTYPE_VARTEXT) + keyseg->type != HA_KEYTYPE_VARTEXT1 && + keyseg->type != HA_KEYTYPE_VARTEXT2) { my_errno=HA_WRONG_CREATE_OPTION; goto err; } + if (!(keyseg->flag & HA_BLOB_PART) && + (keyseg->type == HA_KEYTYPE_VARTEXT1 || + keyseg->type == HA_KEYTYPE_VARTEXT2)) + { + /* Make a flag that this is a VARCHAR */ + keyseg->flag|= HA_VAR_LENGTH_PART; + /* Store in bit_start number of bytes used to pack the length */ + keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1)? + 1 : 2); + } } fulltext_keys++; @@ -314,7 +321,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* Only use HA_PACK_KEY when first segment is a variable length key */ if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART | - HA_VAR_LENGTH))) + HA_VAR_LENGTH_PART))) { /* pack relative to previous key */ keydef->flag&= ~HA_PACK_KEY; @@ -348,12 +355,27 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, case HA_KEYTYPE_UINT24: case HA_KEYTYPE_INT8: keyseg->flag|= HA_SWAP_KEY; - /* fall through */ + break; + case HA_KEYTYPE_VARTEXT1: + case HA_KEYTYPE_VARTEXT2: + case HA_KEYTYPE_VARBINARY1: + case HA_KEYTYPE_VARBINARY2: + if (!(keyseg->flag & HA_BLOB_PART)) + { + /* Make a flag that this is a VARCHAR */ + keyseg->flag|= HA_VAR_LENGTH_PART; + /* Store in bit_start number of bytes used to pack the length */ + keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 || + keyseg->type == HA_KEYTYPE_VARBINARY1) ? + 1 : 2); + } + break; default: break; } if (keyseg->flag & HA_SPACE_PACK) { + DBUG_ASSERT(!(keyseg->flag & HA_VAR_LENGTH_PART)); keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY; options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ length++; /* At least one length byte */ @@ -364,8 +386,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, length+=2; } } - if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART)) + if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) { + DBUG_ASSERT(!test_all_bits(keyseg->flag, + (HA_VAR_LENGTH_PART | HA_BLOB_PART))); keydef->flag|=HA_VAR_LENGTH_KEY; length++; /* At least one length byte */ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ @@ -620,10 +644,12 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, { HA_KEYSEG sseg; sseg.type=SPTYPE; - sseg.language= 7; + sseg.language= 7; /* Binary */ sseg.null_bit=0; sseg.bit_start=0; sseg.bit_end=0; + sseg.bit_length= 0; + sseg.bit_pos= 0; sseg.length=SPLEN; sseg.null_pos=0; sseg.start=j*SPLEN; @@ -656,11 +682,31 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* Save unique definition */ for (i=0 ; i < share.state.header.uniques ; i++) { + HA_KEYSEG *keyseg_end; + keyseg= uniquedefs[i].seg; if (mi_uniquedef_write(file, &uniquedefs[i])) goto err; - for (j=0 ; j < uniquedefs[i].keysegs ; j++) + for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs; + keyseg < keyseg_end; + keyseg++) { - if (mi_keyseg_write(file, &uniquedefs[i].seg[j])) + switch (keyseg->type) { + case HA_KEYTYPE_VARTEXT1: + case HA_KEYTYPE_VARTEXT2: + case HA_KEYTYPE_VARBINARY1: + case HA_KEYTYPE_VARBINARY2: + if (!(keyseg->flag & HA_BLOB_PART)) + { + keyseg->flag|= HA_VAR_LENGTH_PART; + keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 || + keyseg->type == HA_KEYTYPE_VARBINARY1) ? + 1 : 2); + } + break; + default: + break; + } + if (mi_keyseg_write(file, keyseg)) goto err; } } diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index 02d1c7d05d6..e782d21afe7 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -131,9 +131,21 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg, key=end; break; } + case HA_KEYTYPE_BIT: + { + uint i; + fputs("0x",stream); + for (i=0 ; i < keyseg->length ; i++) + fprintf(stream, "%02x", (uint) *key++); + key= end; + break; + } + #endif - case HA_KEYTYPE_VARTEXT: /* VARCHAR and TEXT */ - case HA_KEYTYPE_VARBINARY: /* VARBINARY and BLOB */ + case HA_KEYTYPE_VARTEXT1: /* VARCHAR and TEXT */ + case HA_KEYTYPE_VARTEXT2: /* VARCHAR and TEXT */ + case HA_KEYTYPE_VARBINARY1: /* VARBINARY and BLOB */ + case HA_KEYTYPE_VARBINARY2: /* VARBINARY and BLOB */ { uint tmp_length; get_key_length(tmp_length,key); diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index b964cb35dd8..cc4a17182f7 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -45,6 +45,12 @@ int mi_delete(MI_INFO *info,const byte *record) /* Test if record is in datafile */ + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage", + mi_print_error(info->s, HA_ERR_CRASHED); + DBUG_RETURN(my_errno= HA_ERR_CRASHED);); + DBUG_EXECUTE_IF("my_error_test_undefined_error", + mi_print_error(info->s, INT_MAX); + DBUG_RETURN(my_errno= INT_MAX);); if (!(info->update & HA_STATE_AKTIV)) { DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No database read */ @@ -109,13 +115,19 @@ err: mi_sizestore(lastpos,info->lastpos); myisam_log_command(MI_LOG_DELETE,info,(byte*) lastpos, sizeof(lastpos),0); if (save_errno != HA_ERR_RECORD_CHANGED) + { + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* mark table crashed */ + } VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); info->update|=HA_STATE_WRITTEN; /* Buffer changed */ allow_break(); /* Allow SIGHUP & SIGINT */ my_errno=save_errno; if (save_errno == HA_ERR_KEY_NOT_FOUND) + { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; + } DBUG_RETURN(my_errno); } /* mi_delete */ @@ -142,6 +154,7 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo, if ((old_root=*root) == HA_OFFSET_ERROR) { + mi_print_error(info->s, HA_ERR_CRASHED); DBUG_RETURN(my_errno=HA_ERR_CRASHED); } if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+ @@ -253,7 +266,12 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, my_off_t root; uchar *kpos=keypos; - tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey); + if (!(tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey))) + { + mi_print_error(info->s, HA_ERR_CRASHED); + my_errno= HA_ERR_CRASHED; + DBUG_RETURN(-1); + } root=_mi_dpos(info,nod_flag,kpos); if (subkeys == -1) { @@ -302,6 +320,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (!nod_flag) { DBUG_PRINT("error",("Didn't find key")); + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; /* This should newer happend */ goto err; } @@ -313,13 +332,10 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, { /* Found key */ uint tmp; length=mi_getint(anc_buff); - tmp=remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length, - &next_block); - if (tmp == 0) - { - DBUG_PRINT("exit",("Return: %d",0)); - DBUG_RETURN(0); - } + if (!(tmp= remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length, + &next_block))) + goto err; + length-= tmp; mi_putint(anc_buff,length,nod_flag); @@ -368,6 +384,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, my_afree((byte*) leaf_buff); DBUG_PRINT("exit",("Return: %d",ret_value)); DBUG_RETURN(ret_value); + err: my_afree((byte*) leaf_buff); DBUG_PRINT("exit",("Error: %d",my_errno)); @@ -559,10 +576,10 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo, /* remove key from anc_buff */ - s_length=remove_key(keyinfo,key_reflength,keypos,anc_key, - anc_buff+anc_length,(my_off_t *) 0); - if (!s_length) + if (!(s_length=remove_key(keyinfo,key_reflength,keypos,anc_key, + anc_buff+anc_length,(my_off_t *) 0))) goto err; + anc_length-=s_length; mi_putint(anc_buff,anc_length,key_reflength); @@ -668,10 +685,10 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo, mi_putint(buff,buff_length,nod_flag); /* remove key from anc_buff */ - s_length=remove_key(keyinfo,key_reflength,keypos,anc_key, - anc_buff+anc_length,(my_off_t *) 0); - if (!s_length) + if (!(s_length= remove_key(keyinfo,key_reflength,keypos,anc_key, + anc_buff+anc_length,(my_off_t *) 0))) goto err; + anc_length-=s_length; mi_putint(anc_buff,anc_length,key_reflength); @@ -731,6 +748,7 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,buff)) goto err; DBUG_RETURN(anc_length <= (uint) keyinfo->block_length/2); + err: DBUG_RETURN(-1); } /* underflow */ @@ -768,6 +786,7 @@ static uint remove_key(MI_KEYDEF *keyinfo, uint nod_flag, /* Calculate length of key */ if (!(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey)) DBUG_RETURN(0); /* Error */ + if (next_block && nod_flag) *next_block= _mi_kpos(nod_flag,keypos); s_length=(int) (keypos-start); diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 43783ca2d36..8de500a7351 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -149,7 +149,9 @@ static int write_dynamic_record(MI_INFO *info, const byte *record, { if (_mi_find_writepos(info,reclength,&filepos,&length)) goto err; - if (_mi_write_part_record(info,filepos,length,info->s->state.dellink, + if (_mi_write_part_record(info,filepos,length, + (info->append_insert_at_end ? + HA_OFFSET_ERROR : info->s->state.dellink), (byte**) &record,&reclength,&flag)) goto err; } while (reclength); @@ -171,7 +173,8 @@ static int _mi_find_writepos(MI_INFO *info, ulong tmp; DBUG_ENTER("_mi_find_writepos"); - if (info->s->state.dellink != HA_OFFSET_ERROR) + if (info->s->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end) { /* Deleted blocks exists; Get last used block */ *filepos=info->s->state.dellink; @@ -420,8 +423,9 @@ int _mi_write_part_record(MI_INFO *info, else if (length-long_block < *reclength+4) { /* To short block */ if (next_filepos == HA_OFFSET_ERROR) - next_filepos=info->s->state.dellink != HA_OFFSET_ERROR ? - info->s->state.dellink : info->state->data_file_length; + next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end ? + info->s->state.dellink : info->state->data_file_length); if (*flag == 0) /* First block */ { if (*reclength > MI_MAX_BLOCK_LENGTH) @@ -768,11 +772,21 @@ uint _mi_rec_pack(MI_INFO *info, register byte *to, register const byte *from) } else if (type == FIELD_VARCHAR) { - uint tmp_length=uint2korr(from); - store_key_length_inc(to,tmp_length); - memcpy(to,from+2,tmp_length); - to+=tmp_length; - continue; + uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length -1); + uint tmp_length; + if (pack_length == 1) + { + tmp_length= (uint) *(uchar*) from; + *to++= *from; + } + else + { + tmp_length= uint2korr(from); + store_key_length_inc(to,tmp_length); + } + memcpy(to, from+pack_length,tmp_length); + to+= tmp_length; + continue; } else { @@ -878,9 +892,20 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff, } else if (type == FIELD_VARCHAR) { - uint tmp_length=uint2korr(record); - to+=get_pack_length(tmp_length)+tmp_length; - continue; + uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length -1); + uint tmp_length; + if (pack_length == 1) + { + tmp_length= (uint) *(uchar*) record; + to+= 1+ tmp_length; + continue; + } + else + { + tmp_length= uint2korr(record); + to+= get_pack_length(tmp_length)+tmp_length; + } + continue; } else { @@ -894,9 +919,7 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff, } } else - { - to+=length; - } + to+= length; } if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) || (bit != 1 && (flag & ~(bit - 1)))) @@ -944,13 +967,27 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from, { if (type == FIELD_VARCHAR) { - get_key_length(length,from); - if (length > rec_length-2) - goto err; - int2store(to,length); - memcpy(to+2,from,length); - from+=length; - continue; + uint pack_length= HA_VARCHAR_PACKLENGTH(rec_length-1); + if (pack_length == 1) + { + length= (uint) *(uchar*) from; + if (length > rec_length-1) + goto err; + *to= *from++; + } + else + { + get_key_length(length, from); + if (length > rec_length-2) + goto err; + int2store(to,length); + } + if (from+length > from_end) + goto err; + memcpy(to+pack_length, from, length); + from+= length; + min_pack_length--; + continue; } if (flag & bit) { @@ -1018,15 +1055,17 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from, if (min_pack_length > (uint) (from_end - from)) goto err; min_pack_length-=rec_length; - memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length; + memcpy(to, (byte*) from, (size_t) rec_length); + from+=rec_length; } } if (info->s->calc_checksum) from++; if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1)))) DBUG_RETURN(found_length); + err: - my_errno=HA_ERR_RECORD_DELETED; + my_errno= HA_ERR_WRONG_IN_RECORD; DBUG_PRINT("error",("to_end: %lx -> %lx from_end: %lx -> %lx", to,to_end,from,from_end)); DBUG_DUMP("from",(byte*) info->rec_buff,info->s->base.min_pack_length); diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 4b011ca424f..ba32bb9115a 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -15,7 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "myisamdef.h" -#ifdef HAVE_MMAP +#ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #endif @@ -186,7 +186,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) if (info->opt_flag & WRITE_CACHE_USED) { if ((error=flush_io_cache(&info->rec_cache))) + { + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ + } } break; case HA_EXTRA_NO_READCHECK: @@ -285,6 +288,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) { error=my_errno; share->changed=1; + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ } if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) @@ -339,6 +343,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) if (error) { share->changed=1; + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Fatal error found */ } } diff --git a/myisam/mi_info.c b/myisam/mi_info.c index cf63ef63618..bdece9c2ee3 100644 --- a/myisam/mi_info.c +++ b/myisam/mi_info.c @@ -105,3 +105,36 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag) } DBUG_RETURN(0); } + + +/* + Write a message to the error log. + + SYNOPSIS + mi_report_error() + file_name Name of table file (e.g. index_file_name). + errcode Error number. + + DESCRIPTION + This function supplies my_error() with a table name. Most error + messages need one. Since string arguments in error messages are limited + to 64 characters by convention, we ensure that in case of truncation, + that the end of the index file path is in the message. This contains + the most valuable information (the table name and the database name). + + RETURN + void +*/ + +void mi_report_error(int errcode, const char *file_name) +{ + size_t lgt; + DBUG_ENTER("mi_report_error"); + DBUG_PRINT("enter",("errcode %d, table '%s'", errcode, file_name)); + + if ((lgt= strlen(file_name)) > 64) + file_name+= lgt - 64; + my_error(errcode, MYF(ME_NOREFRESH), file_name); + DBUG_VOID_RETURN; +} + diff --git a/myisam/mi_key.c b/myisam/mi_key.c index b7240f34538..9fb673483ea 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -34,10 +34,20 @@ static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record); - /* - ** Make a intern key from a record - ** Ret: Length of key - */ +/* + Make a intern key from a record + + SYNOPSIS + _mi_make_key() + info MyiSAM handler + keynr key number + key Store created key here + record Record + filepos Position to record in the data file + + RETURN + Length of key +*/ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, const byte *record, my_off_t filepos) @@ -82,6 +92,19 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, length); pos= (byte*) record+keyseg->start; + if (type == HA_KEYTYPE_BIT) + { + if (keyseg->bit_length) + { + uchar bits= get_rec_bits((uchar*) record + keyseg->bit_pos, + keyseg->bit_start, keyseg->bit_length); + *key++= bits; + length--; + } + memcpy((byte*) key, pos, length); + key+= length; + continue; + } if (keyseg->flag & HA_SPACE_PACK) { end=pos+length; @@ -102,10 +125,12 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, key+=char_length; continue; } - if (keyseg->flag & HA_VAR_LENGTH) + if (keyseg->flag & HA_VAR_LENGTH_PART) { - uint tmp_length=uint2korr(pos); - pos+=2; /* Skip VARCHAR length */ + uint pack_length= keyseg->bit_start; + uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos : + uint2korr(pos)); + pos+= pack_length; /* Skip VARCHAR length */ set_if_smaller(length,tmp_length); FIX_LENGTH(cs, pos, length, char_length); store_key_length_inc(key,char_length); @@ -161,7 +186,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, FIX_LENGTH(cs, pos, length, char_length); memcpy((byte*) key, pos, char_length); if (length > char_length) - cs->cset->fill(cs, key+char_length, length-char_length, ' '); + cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' '); key+= length; } _mi_dpointer(info,key,filepos); @@ -216,8 +241,11 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, if (!(*key++= (char) 1-*old++)) /* Copy null marker */ { k_length-=length; - if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART)) + if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) + { k_length-=2; /* Skip length */ + old+= 2; + } continue; /* Found NULL */ } } @@ -244,7 +272,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, key+= char_length; continue; } - else if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART)) + else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) { /* Length of key-part used with mi_rkey() always 2 */ uint tmp_length=uint2korr(pos); @@ -271,7 +299,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, FIX_LENGTH(cs, pos, length, char_length); memcpy((byte*) key, pos, char_length); if (length > char_length) - cs->cset->fill(cs,key+char_length, length-char_length, ' '); + cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' '); key+= length; k_length-=length; } @@ -344,6 +372,26 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, } record[keyseg->null_pos]&= ~keyseg->null_bit; } + if (keyseg->type == HA_KEYTYPE_BIT) + { + uint length= keyseg->length; + + if (keyseg->bit_length) + { + uchar bits= *key++; + set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start, + keyseg->bit_length); + length--; + } + else + { + clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start, + keyseg->bit_length); + } + memcpy(record + keyseg->start, (byte*) key, length); + key+= length; + continue; + } if (keyseg->flag & HA_SPACE_PACK) { uint length; @@ -367,7 +415,7 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, continue; } - if (keyseg->flag & HA_VAR_LENGTH) + if (keyseg->flag & HA_VAR_LENGTH_PART) { uint length; get_key_length(length,key); @@ -375,7 +423,13 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, if (length > keyseg->length || key+length > key_end) goto err; #endif - memcpy(record+keyseg->start,(byte*) key, length); + /* Store key length */ + if (keyseg->bit_start == 1) + *(uchar*) (record+keyseg->start)= (uchar) length; + else + int2store(record+keyseg->start, length); + /* And key data */ + memcpy(record+keyseg->start + keyseg->bit_start, (byte*) key, length); key+= length; } else if (keyseg->flag & HA_BLOB_PART) @@ -437,6 +491,7 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf) { /* Read only key */ if (_mi_put_key_in_record(info,(uint) info->lastinx,buf)) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return -1; } diff --git a/myisam/mi_keycache.c b/myisam/mi_keycache.c index 99a2fd6db15..fb13f3703a2 100644 --- a/myisam/mi_keycache.c +++ b/myisam/mi_keycache.c @@ -79,6 +79,7 @@ int mi_assign_to_key_cache(MI_INFO *info, if (flush_key_blocks(share->key_cache, share->kfile, FLUSH_RELEASE)) { error= my_errno; + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Mark that table must be checked */ } diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index 66950f62321..8d48c5242e5 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -66,6 +66,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) share->kfile,FLUSH_KEEP)) { error=my_errno; + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Mark that table must be checked */ } if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) @@ -73,6 +74,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) if (end_io_cache(&info->rec_cache)) { error=my_errno; + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); } } @@ -98,7 +100,10 @@ int mi_lock_database(MI_INFO *info, int lock_type) else share->not_flushed=1; if (error) + { + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); + } } if (info->lock_type != F_EXTRA_LCK) { @@ -233,13 +238,24 @@ int mi_lock_database(MI_INFO *info, int lock_type) The following functions are called by thr_lock() in threaded applications ****************************************************************************/ -void mi_get_status(void* param) +/* + Create a copy of the current status for the table + + SYNOPSIS + mi_get_status() + param Pointer to Myisam handler + concurrent_insert Set to 1 if we are going to do concurrent inserts + (THR_WRITE_CONCURRENT_INSERT was used) +*/ + +void mi_get_status(void* param, int concurrent_insert) { MI_INFO *info=(MI_INFO*) param; DBUG_ENTER("mi_get_status"); - DBUG_PRINT("info",("key_file: %ld data_file: %ld", + DBUG_PRINT("info",("key_file: %ld data_file: %ld concurrent_insert: %d", (long) info->s->state.state.key_file_length, - (long) info->s->state.state.data_file_length)); + (long) info->s->state.state.data_file_length, + concurrent_insert)); #ifndef DBUG_OFF if (info->state->key_file_length > info->s->state.state.key_file_length || info->state->data_file_length > info->s->state.state.data_file_length) @@ -249,9 +265,11 @@ void mi_get_status(void* param) #endif info->save_state=info->s->state.state; info->state= &info->save_state; + info->append_insert_at_end= concurrent_insert; DBUG_VOID_RETURN; } + void mi_update_status(void* param) { MI_INFO *info=(MI_INFO*) param; @@ -276,6 +294,7 @@ void mi_update_status(void* param) info->s->state.state= *info->state; info->state= &info->s->state.state; } + info->append_insert_at_end= 0; /* We have to flush the write cache here as other threads may start @@ -285,6 +304,7 @@ void mi_update_status(void* param) { if (end_io_cache(&info->rec_cache)) { + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); } info->opt_flag&= ~WRITE_CACHE_USED; @@ -301,20 +321,37 @@ void mi_copy_status(void* to,void *from) Check if should allow concurrent inserts IMPLEMENTATION - Don't allow concurrent inserts if we have a hole in the table. + Allow concurrent inserts if we don't have a hole in the table or + if there is no active write lock and there is active read locks and + myisam_concurrent_insert == 2. In this last case the new + row('s) are inserted at end of file instead of filling up the hole. + + The last case is to allow one to inserts into a heavily read-used table + even if there is holes. NOTES - Rtree indexes are disabled in mi_open() + If there is a an rtree indexes in the table, concurrent inserts are + disabled in mi_open() RETURN 0 ok to use concurrent inserts 1 not ok */ -my_bool mi_check_status(void* param) +my_bool mi_check_status(void *param) { MI_INFO *info=(MI_INFO*) param; - return (my_bool) (info->s->state.dellink != HA_OFFSET_ERROR); + /* + The test for w_locks == 1 is here because this thread has already done an + external lock (in other words: w_locks == 1 means no other threads has + a write lock) + */ + DBUG_PRINT("info",("dellink: %ld r_locks: %u w_locks: %u", + (long) info->s->state.dellink, (uint) info->s->r_locks, + (uint) info->s->w_locks)); + return (my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR || + (myisam_concurrent_insert == 2 && info->s->r_locks && + info->s->w_locks == 1)); } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 2c85a03c6f4..d65a46a92fb 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -106,6 +106,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share_buff.state.key_del=key_del; share_buff.key_cache= multi_key_cache_search(name_buff, strlen(name_buff)); + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open", + if (strstr(name, "/t1")) + { + my_errno= HA_ERR_CRASHED; + goto err; + }); if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0) { if ((errno != EROFS && errno != EACCES) || @@ -302,6 +308,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) HA_KEYSEG *pos=share->keyparts; for (i=0 ; i < keys ; i++) { + share->keyinfo[i].share= share; disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]); disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE, end_pos); @@ -313,7 +320,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) { disk_pos=mi_keyseg_read(disk_pos, pos); - if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT) + if (pos->type == HA_KEYTYPE_TEXT || + pos->type == HA_KEYTYPE_VARTEXT1 || + pos->type == HA_KEYTYPE_VARTEXT2) { if (!pos->language) pos->charset=default_charset_info; @@ -388,7 +397,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++) { disk_pos=mi_keyseg_read(disk_pos, pos); - if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT) + if (pos->type == HA_KEYTYPE_TEXT || + pos->type == HA_KEYTYPE_VARTEXT1 || + pos->type == HA_KEYTYPE_VARTEXT2) { if (!pos->language) pos->charset=default_charset_info; @@ -596,6 +607,10 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) err: save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE; + if ((save_errno == HA_ERR_CRASHED) || + (save_errno == HA_ERR_CRASHED_ON_USAGE) || + (save_errno == HA_ERR_CRASHED_ON_REPAIR)) + mi_report_error(save_errno, name); switch (errpos) { case 6: my_free((gptr) m_info,MYF(0)); @@ -1042,18 +1057,21 @@ int mi_keyseg_write(File file, const HA_KEYSEG *keyseg) { uchar buff[HA_KEYSEG_SIZE]; uchar *ptr=buff; - - *ptr++ =keyseg->type; - *ptr++ =keyseg->language; - *ptr++ =keyseg->null_bit; - *ptr++ =keyseg->bit_start; - *ptr++ =keyseg->bit_end; - *ptr++ =0; /* Not used */ + ulong pos; + + *ptr++= keyseg->type; + *ptr++= keyseg->language; + *ptr++= keyseg->null_bit; + *ptr++= keyseg->bit_start; + *ptr++= keyseg->bit_end; + *ptr++= keyseg->bit_length; mi_int2store(ptr,keyseg->flag); ptr+=2; mi_int2store(ptr,keyseg->length); ptr+=2; mi_int4store(ptr,keyseg->start); ptr+=4; - mi_int4store(ptr,keyseg->null_pos); ptr+=4; - + pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos; + mi_int4store(ptr, pos); + ptr+=4; + return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP)); } @@ -1065,12 +1083,19 @@ char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg) keyseg->null_bit = *ptr++; keyseg->bit_start = *ptr++; keyseg->bit_end = *ptr++; - ptr++; + keyseg->bit_length = *ptr++; keyseg->flag = mi_uint2korr(ptr); ptr +=2; keyseg->length = mi_uint2korr(ptr); ptr +=2; keyseg->start = mi_uint4korr(ptr); ptr +=4; keyseg->null_pos = mi_uint4korr(ptr); ptr +=4; keyseg->charset=0; /* Will be filled in later */ + if (keyseg->null_bit) + keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7)); + else + { + keyseg->bit_pos= (uint16)keyseg->null_pos; + keyseg->null_pos= 0; + } return ptr; } @@ -1210,7 +1235,10 @@ int mi_enable_indexes(MI_INFO *info) if (share->state.state.data_file_length || (share->state.state.key_file_length != share->base.keystart)) + { + mi_print_error(info->s, HA_ERR_CRASHED); error= HA_ERR_CRASHED; + } else share->state.key_map= ((ulonglong) 1L << share->base.keys) - 1; return error; diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 1a71d43a7f1..4b512dd89dd 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -91,8 +91,10 @@ static void uf_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff, uchar *to,uchar *end); static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to, uchar *end); -static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, - uchar *to, uchar *end); +static void uf_varchar1(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, + uchar *to, uchar *end); +static void uf_varchar2(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, + uchar *to, uchar *end); static void decode_bytes(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff, uchar *to,uchar *end); static uint decode_pos(MI_BIT_BUFF *bit_buff,MI_DECODE_TREE *decode_tree); @@ -515,14 +517,16 @@ static void (*get_unpack_function(MI_COLUMNDEF *rec)) case FIELD_BLOB: return &uf_blob; case FIELD_VARCHAR: - return &uf_varchar; + if (rec->length <= 256) /* 255 + 1 byte length */ + return &uf_varchar1; + return &uf_varchar2; case FIELD_LAST: default: return 0; /* This should never happend */ } } - /* De different functions to unpack a field */ + /* The different functions to unpack a field */ static void uf_zerofill_skip_zero(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to, uchar *end) @@ -766,7 +770,22 @@ static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, } } -static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, + +static void uf_varchar1(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, + uchar *to, uchar *end __attribute__((unused))) +{ + if (get_bit(bit_buff)) + to[0]= 0; /* Zero lengths */ + else + { + ulong length=get_bits(bit_buff,rec->space_length_bits); + *to= (uchar) length; + decode_bytes(rec,bit_buff,to+1,to+1+length); + } +} + + +static void uf_varchar2(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to, uchar *end __attribute__((unused))) { if (get_bit(bit_buff)) @@ -1162,11 +1181,12 @@ static uint max_bit(register uint value) /***************************************************************************** Some redefined functions to handle files when we are using memmap *****************************************************************************/ +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif #ifdef HAVE_MMAP -#include <sys/mman.h> - static int _mi_read_mempack_record(MI_INFO *info,my_off_t filepos,byte *buf); static int _mi_read_rnd_mempack_record(MI_INFO*, byte *,my_off_t, my_bool); @@ -1192,7 +1212,7 @@ my_bool _mi_memmap_file(MI_INFO *info) DBUG_RETURN(0); } file_map=(byte*) - mmap(0,share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN,PROT_READ, + my_mmap(0,(size_t)(share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN),PROT_READ, MAP_SHARED | MAP_NORESERVE,info->dfile,0L); if (file_map == (byte*) MAP_FAILED) { @@ -1211,7 +1231,7 @@ my_bool _mi_memmap_file(MI_INFO *info) void _mi_unmap_file(MI_INFO *info) { - VOID(munmap((caddr_t) info->s->file_map, + VOID(my_munmap(info->s->file_map, (size_t) info->s->state.state.data_file_length+ MEMMAP_EXTRA_MARGIN)); } diff --git a/myisam/mi_page.c b/myisam/mi_page.c index 16713c87e10..5240c063fba 100644 --- a/myisam/mi_page.c +++ b/myisam/mi_page.c @@ -40,6 +40,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo, { DBUG_PRINT("error",("Got errno: %d from key_cache_read",my_errno)); info->last_keypage=HA_OFFSET_ERROR; + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } @@ -51,6 +52,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo, (ulong) page, page_size)); DBUG_DUMP("page", (char*) tmp, keyinfo->block_length); info->last_keypage = HA_OFFSET_ERROR; + mi_print_error(info->s, HA_ERR_CRASHED); my_errno = HA_ERR_CRASHED; tmp = 0; } diff --git a/myisam/mi_range.c b/myisam/mi_range.c index 1e0fd42334e..e78f3b11625 100644 --- a/myisam/mi_range.c +++ b/myisam/mi_range.c @@ -172,9 +172,9 @@ static double _mi_search_pos(register MI_INFO *info, if (flag == MI_FOUND_WRONG_KEY) DBUG_RETURN(-1); /* error */ /* - ** Didn't found match. keypos points at next (bigger) key - * Try to find a smaller, better matching key. - ** Matches keynr + [0-1] + Didn't found match. keypos points at next (bigger) key + Try to find a smaller, better matching key. + Matches keynr + [0-1] */ if (flag > 0 && ! nod_flag) offset= 1.0; @@ -185,8 +185,8 @@ static double _mi_search_pos(register MI_INFO *info, else { /* - ** Found match. Keypos points at the start of the found key - ** Matches keynr+1 + Found match. Keypos points at the start of the found key + Matches keynr+1 */ offset=1.0; /* Matches keynr+1 */ if ((nextflag & SEARCH_FIND) && nod_flag && @@ -194,8 +194,8 @@ static double _mi_search_pos(register MI_INFO *info, key_len != USE_WHOLE_KEY)) { /* - ** There may be identical keys in the tree. Try to match on of those. - ** Matches keynr + [0-1] + There may be identical keys in the tree. Try to match on of those. + Matches keynr + [0-1] */ if ((offset=_mi_search_pos(info,keyinfo,key,key_len,SEARCH_FIND, _mi_kpos(nod_flag,keypos))) < 0) @@ -213,7 +213,8 @@ err: /* Get keynummer of current key and max number of keys in nod */ -static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, uchar *keypos, uint *ret_max_key) +static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, + uchar *keypos, uint *ret_max_key) { uint nod_flag,keynr,max_key; uchar t_buff[MI_MAX_KEY_BUFF],*end; @@ -222,7 +223,7 @@ static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, u nod_flag=mi_test_if_nod(page); page+=2+nod_flag; - if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY| HA_BINARY_PACK_KEY))) + if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY))) { *ret_max_key= (uint) (end-page)/(keyinfo->keylength+nod_flag); return (uint) (keypos-page)/(keyinfo->keylength+nod_flag); diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c index 12db00337ee..635a7eb2c48 100644 --- a/myisam/mi_rkey.c +++ b/myisam/mi_rkey.c @@ -78,6 +78,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, case HA_KEY_ALG_RTREE: if (rtree_find_first(info,inx,key_buff,use_key_length,nextflag) < 0) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; goto err; } diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 390e32b679d..c669a8be8f8 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -159,6 +159,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos)); DBUG_RETURN(0); + err: DBUG_PRINT("exit",("Error: %d",my_errno)); info->lastpos= HA_OFFSET_ERROR; @@ -256,6 +257,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff); if (length == 0 || page > end) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p", length, page, end)); @@ -386,7 +388,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, if (!(*from++)) continue; } - if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) + if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) { get_key_length(l,from); } @@ -402,6 +404,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, if (page > end) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p", length, page, end)); @@ -447,7 +450,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, if (len < cmplen) { if ((keyinfo->seg->type != HA_KEYTYPE_TEXT && - keyinfo->seg->type != HA_KEYTYPE_VARTEXT)) + keyinfo->seg->type != HA_KEYTYPE_VARTEXT1 && + keyinfo->seg->type != HA_KEYTYPE_VARTEXT2)) my_flag= -1; else { @@ -781,6 +785,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { if (length > (uint) keyseg->length) { + mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return 0; /* Error */ } @@ -796,6 +801,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, ("Found too long null packed key: %u of %u at %p", length, keyseg->length, *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); + mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return 0; } @@ -852,6 +858,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, DBUG_PRINT("error",("Found too long packed key: %u of %u at %p", length, keyseg->length, *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); + mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return 0; /* Error */ } @@ -865,7 +872,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, continue; } if (keyseg->flag & - (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) + (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) { uchar *tmp=page; get_key_length(length,tmp); @@ -907,6 +914,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, DBUG_PRINT("error",("Found too long binary packed key: %u of %u at %p", length, keyinfo->maxlength, *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); + mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return 0; /* Wrong key */ } @@ -930,7 +938,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if (!(*key++ = *from++)) continue; /* Null part */ } - if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) + if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) { /* Get length of dynamic length key part */ if (from == from_end) { from=page; from_end=page_end; } @@ -968,6 +976,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if (from_end != page_end) { DBUG_PRINT("error",("Error when unpacking key")); + mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return 0; /* Error */ } @@ -1002,6 +1011,7 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } @@ -1039,6 +1049,7 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(1); } @@ -1079,6 +1090,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, if (*return_key_length == 0) { DBUG_PRINT("error",("Couldn't find last key: page: %p", page)); + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } @@ -1105,7 +1117,7 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) if (keyseg->flag & HA_NULL_PART) if (!*key++) continue; - if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH)) + if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART)) { uint length; get_key_length(length,key); @@ -1137,7 +1149,7 @@ uint _mi_keylength_part(MI_KEYDEF *keyinfo, register uchar *key, if (keyseg->flag & HA_NULL_PART) if (!*key++) continue; - if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH)) + if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART)) { uint length; get_key_length(length,key); @@ -1269,8 +1281,10 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, page=info->buff+2+nod_flag; } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR); - info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page, - info->lastkey); + if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page, + info->lastkey))) + DBUG_RETURN(-1); /* Crashed */ + 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; @@ -1405,7 +1419,8 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, sort_order=0; if ((keyinfo->flag & HA_FULLTEXT) && ((keyseg->type == HA_KEYTYPE_TEXT) || - (keyseg->type == HA_KEYTYPE_VARTEXT)) && + (keyseg->type == HA_KEYTYPE_VARTEXT1) || + (keyseg->type == HA_KEYTYPE_VARTEXT2)) && !use_strnxfrm(keyseg->charset)) sort_order=keyseg->charset->sort_order; diff --git a/myisam/mi_static.c b/myisam/mi_static.c index f41aeff8453..4c9d814f7d6 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -31,14 +31,13 @@ uchar NEAR myisam_pack_file_magic[]= 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 */ +ulong myisam_block_size= MI_KEY_BLOCK_LENGTH; /* Best by test */ 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; +ulong myisam_concurrent_insert= 2; #else -my_bool myisam_concurrent_insert=0; +ulong myisam_concurrent_insert= 0; #endif -my_off_t myisam_max_extra_temp_length= (my_off_t)MI_MAX_TEMP_LENGTH; my_off_t myisam_max_temp_length= MAX_FILE_SIZE; ulong myisam_bulk_insert_tree_size=8192*1024; ulong myisam_data_pointer_size=4; diff --git a/myisam/mi_statrec.c b/myisam/mi_statrec.c index 8f5cde45e24..42352f63c66 100644 --- a/myisam/mi_statrec.c +++ b/myisam/mi_statrec.c @@ -23,7 +23,8 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) { uchar temp[8]; /* max pointer length */ - if (info->s->state.dellink != HA_OFFSET_ERROR) + if (info->s->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end) { my_off_t filepos=info->s->state.dellink; info->rec_cache.seek_not_done=1; /* We have done a seek */ diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c index 77c4d3dfbad..aa6cd98ac8e 100644 --- a/myisam/mi_test1.c +++ b/myisam/mi_test1.c @@ -75,11 +75,11 @@ static int run_test(const char *filename) recinfo[1].length= (key_field == FIELD_BLOB ? 4+mi_portable_sizeof_char_ptr : key_length); if (key_field == FIELD_VARCHAR) - recinfo[1].length+=2; + recinfo[1].length+= HA_VARCHAR_PACKLENGTH(key_length);; recinfo[2].type=extra_field; recinfo[2].length= (extra_field == FIELD_BLOB ? 4 + mi_portable_sizeof_char_ptr : 24); if (extra_field == FIELD_VARCHAR) - recinfo[2].length+=2; + recinfo[2].length+= HA_VARCHAR_PACKLENGTH(recinfo[2].length); if (opt_unique) { recinfo[3].type=FIELD_CHECK; @@ -88,6 +88,9 @@ static int run_test(const char *filename) rec_length=recinfo[0].length+recinfo[1].length+recinfo[2].length+ recinfo[3].length; + if (key_type == HA_KEYTYPE_VARTEXT1 && + key_length > 255) + key_type= HA_KEYTYPE_VARTEXT2; /* Define a key over the first column */ keyinfo[0].seg=keyseg; @@ -134,7 +137,7 @@ static int run_test(const char *filename) uniqueseg[1].flag|= HA_BLOB_PART; } else if (extra_field == FIELD_VARCHAR) - uniqueseg[1].flag|= HA_VAR_LENGTH; + uniqueseg[1].flag|= HA_VAR_LENGTH_PART; } else uniques=0; @@ -330,7 +333,8 @@ static void create_key_part(char *key,uint rownr) { sprintf(key,"%*d",keyinfo[0].seg[0].length,rownr); } - else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT) + else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT1 || + keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT2) { /* Alpha record */ /* Create a key that may be easily packed */ bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B'); @@ -372,7 +376,7 @@ static void create_key(char *key,uint rownr) } *key++=0; } - if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH)) + if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART)) { uint tmp; create_key_part(key+2,rownr); @@ -410,11 +414,14 @@ static void create_record(char *record,uint rownr) } else if (recinfo[1].type == FIELD_VARCHAR) { - uint tmp; - create_key_part(pos+2,rownr); - tmp=strlen(pos+2); - int2store(pos,tmp); - pos+=recinfo[1].length; + uint tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); + create_key_part(pos+pack_length,rownr); + tmp= strlen(pos+pack_length); + if (pack_length == 1) + *(uchar*) pos= (uchar) tmp; + else + int2store(pos,tmp); + pos+= recinfo[1].length; } else { @@ -434,10 +441,13 @@ static void create_record(char *record,uint rownr) } else if (recinfo[2].type == FIELD_VARCHAR) { - uint tmp; - sprintf(pos+2,"... row: %d", rownr); - tmp=strlen(pos+2); - int2store(pos,tmp); + uint tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); + sprintf(pos+pack_length, "... row: %d", rownr); + tmp= strlen(pos+pack_length); + if (pack_length == 1) + *(uchar*) pos= (uchar) tmp; + else + int2store(pos,tmp); } else { @@ -466,8 +476,9 @@ static void update_record(char *record) } else if (recinfo[1].type == FIELD_VARCHAR) { - uint length=uint2korr(pos); - my_casedn(default_charset_info,pos+2,length); + uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); + uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos); + my_casedn(default_charset_info,pos+pack_length,length); pos+=recinfo[1].length; } else @@ -493,10 +504,14 @@ static void update_record(char *record) else if (recinfo[2].type == FIELD_VARCHAR) { /* Second field is longer than 10 characters */ - uint length=uint2korr(pos); - bfill(pos+2+length,recinfo[2].length-length-2,'.'); - length=recinfo[2].length-2; - int2store(pos,length); + uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1); + uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos); + bfill(pos+pack_length+length,recinfo[2].length-length-pack_length,'.'); + length=recinfo[2].length-pack_length; + if (pack_length == 1) + *(uchar*) pos= (uchar) length; + else + int2store(pos,length); } else { @@ -519,12 +534,12 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"insert_rows", 'i', "Undocumented", (gptr*) &insert_count, (gptr*) &insert_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0}, - {"key_alpha", 'a', "Undocumented", + {"key_alpha", 'a', "Use a key of type HA_KEYTYPE_TEXT", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"key_binary_pack", 'B', "Undocumented", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"key_blob", 'b', "Undocumented", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"key_cache", 'K', "Undocumented", (gptr*) &key_cacheing, (gptr*) &key_cacheing, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"key_length", 'k', "Undocumented", (gptr*) &key_length, (gptr*) &key_length, @@ -535,9 +550,9 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"key_space_pack", 'p', "Undocumented", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"key_varchar", 'w', "Undocumented", + {"key_varchar", 'w', "Test VARCHAR keys", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"null_fields", 'N', "Undocumented", + {"null_fields", 'N', "Define fields with NULL", (gptr*) &null_fields, (gptr*) &null_fields, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"row_fixed_size", 'S', "Undocumented", @@ -604,7 +619,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), key_field=FIELD_BLOB; /* blob key */ extra_field= FIELD_BLOB; pack_seg|= HA_BLOB_PART; - key_type= HA_KEYTYPE_VARTEXT; + key_type= HA_KEYTYPE_VARTEXT1; break; case 'k': if (key_length < 4 || key_length > MI_MAX_KEY_LENGTH) @@ -616,11 +631,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'w': key_field=FIELD_VARCHAR; /* varchar keys */ extra_field= FIELD_VARCHAR; - key_type= HA_KEYTYPE_VARTEXT; - pack_seg|= HA_VAR_LENGTH; + key_type= HA_KEYTYPE_VARTEXT1; + pack_seg|= HA_VAR_LENGTH_PART; create_flag|= HA_PACK_RECORD; break; - case 'K': /* Use key cacheing */ + case 'K': /* Use key cacheing */ key_cacheing=1; break; case 'V': diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c index 27d23317b5c..be4277cc65c 100644 --- a/myisam/mi_test3.c +++ b/myisam/mi_test3.c @@ -67,6 +67,7 @@ int main(int argc,char **argv) bzero((char*) keyinfo,sizeof(keyinfo)); bzero((char*) recinfo,sizeof(recinfo)); + bzero((char*) keyseg,sizeof(keyseg)); keyinfo[0].seg= &keyseg[0][0]; keyinfo[0].seg[0].start=0; keyinfo[0].seg[0].length=8; diff --git a/myisam/mi_test_all.res b/myisam/mi_test_all.res index 94355bf1aa2..16b517d3f76 100644 --- a/myisam/mi_test_all.res +++ b/myisam/mi_test_all.res @@ -1,3 +1,6 @@ +myisamchk: MyISAM file test1 +myisamchk: warning: Size of indexfile is: 1024 Should be: 2048 +MyISAM-table 'test1' is usable but should be fixed mi_test2 -s -L -K -R1 -m2000 ; Should give error 135 Error: 135 in write at record: 1105 got error: 135 when using MyISAM-database @@ -5,46 +8,46 @@ myisamchk: MyISAM file test2 myisamchk: warning: Datafile is almost full, 65532 of 65534 used MyISAM-table 'test2' is usable but should be fixed Commands Used count Errors Recover errors -open 17 0 0 -write 850 0 0 -update 85 0 0 -delete 850 0 0 -close 17 0 0 -extra 102 0 0 -Total 1921 0 0 +open 1 0 0 +write 50 0 0 +update 5 0 0 +delete 50 0 0 +close 1 0 0 +extra 6 0 0 +Total 113 0 0 Commands Used count Errors Recover errors -open 18 0 0 -write 900 0 0 -update 90 0 0 -delete 900 0 0 -close 18 0 0 -extra 108 0 0 -Total 2034 0 0 +open 2 0 0 +write 100 0 0 +update 10 0 0 +delete 100 0 0 +close 2 0 0 +extra 12 0 0 +Total 226 0 0 -real 0m1.054s -user 0m0.410s -sys 0m0.640s +real 0m0.791s +user 0m0.137s +sys 0m0.117s -real 0m1.077s -user 0m0.550s -sys 0m0.530s +real 0m0.659s +user 0m0.252s +sys 0m0.102s -real 0m1.100s -user 0m0.420s -sys 0m0.680s +real 0m0.571s +user 0m0.188s +sys 0m0.098s -real 0m0.783s -user 0m0.590s -sys 0m0.200s +real 0m1.111s +user 0m0.236s +sys 0m0.037s -real 0m0.764s -user 0m0.560s -sys 0m0.210s +real 0m0.621s +user 0m0.242s +sys 0m0.022s -real 0m0.699s -user 0m0.570s -sys 0m0.130s +real 0m0.698s +user 0m0.248s +sys 0m0.021s -real 0m0.991s -user 0m0.630s -sys 0m0.350s +real 0m0.683s +user 0m0.265s +sys 0m0.079s diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c index ad685f4cbdc..f2d5f01be25 100644 --- a/myisam/mi_unique.c +++ b/myisam/mi_unique.c @@ -93,10 +93,12 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record) } } pos= record+keyseg->start; - if (keyseg->flag & HA_VAR_LENGTH) + if (keyseg->flag & HA_VAR_LENGTH_PART) { - uint tmp_length=uint2korr(pos); - pos+=2; /* Skip VARCHAR length */ + uint pack_length= keyseg->bit_start; + uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos : + uint2korr(pos)); + pos+= pack_length; /* Skip VARCHAR length */ set_if_smaller(length,tmp_length); } else if (keyseg->flag & HA_BLOB_PART) @@ -107,7 +109,8 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record) length=tmp_length; /* The whole blob */ } end= pos+length; - if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT) + if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 || + type == HA_KEYTYPE_VARTEXT2) { keyseg->charset->coll->hash_sort(keyseg->charset, (const uchar*) pos, length, &seed1, @@ -136,7 +139,8 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, for (keyseg=def->seg ; keyseg < def->end ; keyseg++) { enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type; - uint length=keyseg->length; + uint a_length, b_length; + a_length= b_length= keyseg->length; /* If part is NULL it's regarded as different */ if (keyseg->null_bit) @@ -154,43 +158,59 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, } pos_a= a+keyseg->start; pos_b= b+keyseg->start; - if (keyseg->flag & HA_VAR_LENGTH) + if (keyseg->flag & HA_VAR_LENGTH_PART) { - uint tmp_length=uint2korr(pos_a); - if (tmp_length != uint2korr(pos_b)) - return 1; - pos_a+=2; /* Skip VARCHAR length */ - pos_b+=2; - set_if_smaller(length,tmp_length); + uint pack_length= keyseg->bit_start; + if (pack_length == 1) + { + a_length= (uint) *(uchar*) pos_a++; + b_length= (uint) *(uchar*) pos_b++; + } + else + { + a_length= uint2korr(pos_a); + b_length= uint2korr(pos_b); + pos_a+= 2; /* Skip VARCHAR length */ + pos_b+= 2; + } + set_if_smaller(a_length, keyseg->length); /* Safety */ + set_if_smaller(b_length, keyseg->length); /* safety */ } else if (keyseg->flag & HA_BLOB_PART) { - /* Only compare 'length' characters if length<> 0 */ - uint a_length= _mi_calc_blob_length(keyseg->bit_start,pos_a); - uint b_length= _mi_calc_blob_length(keyseg->bit_start,pos_b); + /* Only compare 'length' characters if length != 0 */ + a_length= _mi_calc_blob_length(keyseg->bit_start,pos_a); + b_length= _mi_calc_blob_length(keyseg->bit_start,pos_b); /* Check that a and b are of equal length */ - if (length && a_length > length) - a_length=length; - if (!length || length > b_length) - length=b_length; - if (length != a_length) - return 1; - /* Both strings are at least 'length' long */ + if (keyseg->length) + { + /* + This is used in some cases when we are not interested in comparing + the whole length of the blob. + */ + set_if_smaller(a_length, keyseg->length); + set_if_smaller(b_length, keyseg->length); + } memcpy_fixed((byte*) &pos_a,pos_a+keyseg->bit_start,sizeof(char*)); memcpy_fixed((byte*) &pos_b,pos_b+keyseg->bit_start,sizeof(char*)); } - if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT) + if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 || + type == HA_KEYTYPE_VARTEXT2) { - if (mi_compare_text(keyseg->charset, (uchar *) pos_a, length, - (uchar *) pos_b, length, 0, 0)) - return 1; + if (mi_compare_text(keyseg->charset, (uchar *) pos_a, a_length, + (uchar *) pos_b, b_length, 0, 1)) + return 1; } else { - end= pos_a+length; + if (a_length != b_length) + return 1; + end= pos_a+a_length; while (pos_a != end) + { if (*pos_a++ != *pos_b++) return 1; + } } } return 0; diff --git a/myisam/mi_update.c b/myisam/mi_update.c index f62be133ed9..cda60694008 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -34,6 +34,9 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) LINT_INIT(changed); LINT_INIT(old_checksum); + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage", + mi_print_error(info->s, HA_ERR_CRASHED); + DBUG_RETURN(my_errno= HA_ERR_CRASHED);); if (!(info->update & HA_STATE_AKTIV)) { DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); @@ -205,7 +208,10 @@ err: } while (i-- != 0); } else + { + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); + } info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED | key_changed); @@ -214,6 +220,9 @@ err: VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); allow_break(); /* Allow SIGHUP & SIGINT */ if (save_errno == HA_ERR_KEY_NOT_FOUND) + { + mi_print_error(info->s, HA_ERR_CRASHED); save_errno=HA_ERR_CRASHED; + } DBUG_RETURN(my_errno=save_errno); } /* mi_update */ diff --git a/myisam/mi_write.c b/myisam/mi_write.c index cd9e73fba22..dd062b79769 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -52,6 +52,9 @@ int mi_write(MI_INFO *info, byte *record) DBUG_ENTER("mi_write"); DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile)); + DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage", + mi_print_error(info->s, HA_ERR_CRASHED); + DBUG_RETURN(my_errno= HA_ERR_CRASHED);); if (share->options & HA_OPTION_READ_ONLY_DATA) { DBUG_RETURN(my_errno=EACCES); @@ -64,7 +67,8 @@ int mi_write(MI_INFO *info, byte *record) MYF(MY_SEEK_NOT_DONE) | info->lock_wait)) goto err; #endif - filepos= ((share->state.dellink != HA_OFFSET_ERROR) ? + filepos= ((share->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end) ? share->state.dellink : info->state->data_file_length); @@ -203,7 +207,10 @@ err: } } else + { + mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); + } info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED); my_errno=save_errno; err2: @@ -249,7 +256,7 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, comp_flag=SEARCH_BIGGER; /* Put after same key */ else if (keyinfo->flag & (HA_NOSAME|HA_FULLTEXT)) { - comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */ + comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */ if (keyinfo->flag & HA_NULL_ARE_EQUAL) comp_flag|= SEARCH_NULL_ARE_EQUAL; } @@ -348,6 +355,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); else dupp_key_pos= HA_OFFSET_ERROR; + if (keyinfo->flag & HA_FULLTEXT) { uint off; @@ -478,6 +486,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, { if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(-1); } @@ -487,6 +496,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, { if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH) { + mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(-1); } @@ -582,6 +592,7 @@ int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo, &after_key); if (!key_pos) DBUG_RETURN(-1); + length=(uint) (key_pos-buff); a_length=mi_getint(buff); mi_putint(buff,length,nod_flag); @@ -602,6 +613,7 @@ int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo, /* Store new page */ if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff)) DBUG_RETURN(-1); + t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar *) 0, (uchar*) 0, (uchar*) 0, key_buff, &s_temp); @@ -708,6 +720,7 @@ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, memcpy(key, key_buff, length); /* previous key */ if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff))) { + mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); } diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index d53e589e205..519e123e9da 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -50,7 +50,7 @@ static int stopwords_inited= 0; static MY_TMPDIR myisamchk_tmpdir; static const char *type_names[]= -{ "?","char","binary", "short", "long", "float", +{ "impossible","char","binary", "short", "long", "float", "double","number","unsigned short", "unsigned long","longlong","ulonglong","int24", "uint24","int8","varchar", "varbin","?", @@ -1699,11 +1699,11 @@ err: sorting */ -static my_bool not_killed= 0; +static int not_killed= 0; -volatile my_bool *killed_ptr(MI_CHECK *param __attribute__((unused))) +volatile int *killed_ptr(MI_CHECK *param __attribute__((unused))) { - return ¬_killed; /* always NULL */ + return ¬_killed; /* always NULL */ } /* print warnings and errors */ diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index a41bcf5449b..5688b377d3d 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -271,6 +271,7 @@ struct st_myisam_info { uint preload_buff_size; /* When preloading indexes */ myf lock_wait; /* is 0 or MY_DONT_WAIT */ my_bool was_locked; /* Was locked in panic */ + my_bool append_insert_at_end; /* Set if concurrent insert */ my_bool quick_mode; 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 */ @@ -356,6 +357,8 @@ typedef struct st_mi_sort_param #define mi_mark_crashed_on_repair(x) { (x)->s->state.changed|=STATE_CRASHED|STATE_CRASHED_ON_REPAIR ; (x)->update|= HA_STATE_CHANGED; } #define mi_is_crashed(x) ((x)->s->state.changed & STATE_CRASHED) #define mi_is_crashed_on_repair(x) ((x)->s->state.changed & STATE_CRASHED_ON_REPAIR) +#define mi_print_error(SHARE, ERRNO) \ + mi_report_error((ERRNO), (SHARE)->index_file_name) /* Functions to store length of space packed keys, VARCHAR or BLOB keys */ @@ -667,6 +670,7 @@ extern void _myisam_log_command(enum myisam_log_commands command, extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info, const byte *record,my_off_t filepos, int result); +extern void mi_report_error(int errcode, const char *file_name); extern my_bool _mi_memmap_file(MI_INFO *info); extern void _mi_unmap_file(MI_INFO *info); extern uint save_pack_length(byte *block_buff,ulong length); @@ -699,7 +703,7 @@ int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def, const byte *record, my_off_t pos); int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, my_bool null_are_equal); -void mi_get_status(void* param); +void mi_get_status(void* param, int concurrent_insert); void mi_update_status(void* param); void mi_copy_status(void* to,void *from); my_bool mi_check_status(void* param); @@ -712,7 +716,7 @@ int mi_open_keyfile(MYISAM_SHARE *share); void mi_setup_functions(register MYISAM_SHARE *share); /* Functions needed by mi_check */ -volatile my_bool *killed_ptr(MI_CHECK *param); +volatile int *killed_ptr(MI_CHECK *param); 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,...)); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 88f38be3c54..74bb541b220 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -748,7 +748,8 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) static_row_size=1; for (count=huff_counts ; count < end_count ; count++) { - if (count->field_type == FIELD_BLOB || count->field_type == FIELD_VARCHAR) + if (count->field_type == FIELD_BLOB || + count->field_type == FIELD_VARCHAR) { static_row_size=0; break; @@ -849,9 +850,11 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) } else if (count->field_type == FIELD_VARCHAR) { - length=uint2korr(start_pos); - pos=start_pos+2; - end_pos=start_pos+length; + uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1); + length= (pack_length == 1 ? (uint) *(uchar*) start_pos : + uint2korr(start_pos)); + pos= start_pos+pack_length; + end_pos= pos+length; set_if_bigger(count->max_length,length); } if (count->field_length <= 8 && @@ -1833,17 +1836,19 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) } case FIELD_VARCHAR: { - ulong col_length= uint2korr(start_pos); + uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1); + ulong col_length= (pack_length == 1 ? (uint) *(uchar*) start_pos : + uint2korr(start_pos)); if (!col_length) { write_bits(1,1); /* Empty varchar */ } else { - byte *end=start_pos+2+col_length; + byte *end=start_pos+pack_length+col_length; write_bits(0,1); write_bits(col_length,count->length_bits); - for (start_pos+=2 ; start_pos < end ; start_pos++) + for (start_pos+=pack_length ; start_pos < end ; start_pos++) write_bits(tree->code[(uchar) *start_pos], (uint) tree->code_len[(uchar) *start_pos]); } diff --git a/myisam/rt_split.c b/myisam/rt_split.c index 005e86805bb..31a7d09ab4f 100644 --- a/myisam/rt_split.c +++ b/myisam/rt_split.c @@ -257,18 +257,17 @@ int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, int n_dim; uchar *source_cur, *cur1, *cur2; uchar *new_page; - int err_code = 0; - - uint nod_flag = mi_test_if_nod(page); - uint full_length = key_length + (nod_flag ? nod_flag : - info->s->base.rec_reflength); - - int max_keys = (mi_getint(page)-2) / (full_length); + int err_code= 0; + uint nod_flag= mi_test_if_nod(page); + uint full_length= key_length + (nod_flag ? nod_flag : + info->s->base.rec_reflength); + int max_keys= (mi_getint(page)-2) / (full_length); n_dim = keyinfo->keysegs / 2; - if (!(coord_buf= my_alloca(n_dim * 2 * sizeof(double) * (max_keys + 1 + 4) + - sizeof(SplitStruct) * (max_keys + 1)))) + if (!(coord_buf= (double*) my_alloca(n_dim * 2 * sizeof(double) * + (max_keys + 1 + 4) + + sizeof(SplitStruct) * (max_keys + 1)))) return -1; task= (SplitStruct *)(coord_buf + n_dim * 2 * (max_keys + 1 + 4)); @@ -311,8 +310,7 @@ int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, cur1 = rt_PAGE_FIRST_KEY(page, nod_flag); cur2 = rt_PAGE_FIRST_KEY(new_page, nod_flag); - n1 = 0; - n2 = 0; + n1= n2 = 0; for (cur = task; cur < stop; ++cur) { uchar *to; diff --git a/myisam/sort.c b/myisam/sort.c index 7c6efa9a05b..9d2af2e8c70 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -860,7 +860,8 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file, uchar *strpos; BUFFPEK *buffpek,**refpek; QUEUE queue; - volatile my_bool *killed= killed_ptr(info->sort_info->param); + volatile int *killed= killed_ptr(info->sort_info->param); + DBUG_ENTER("merge_buffers"); count=error=0; |