Loading include/myisam.h +15 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,20 @@ typedef struct st_sort_key_blocks /* Used when sorting */ } SORT_KEY_BLOCKS; /* MyISAM supports several statistics collection methods. Currently statistics collection method is not stored in MyISAM file and has to be specified for each table analyze/repair operation in MI_CHECK::stats_method. */ typedef enum { /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */ MI_STATS_METHOD_NULLS_NOT_EQUAL, /* Treat NULLs as equal when collecting statistics (like 4.0 did) */ MI_STATS_METHOD_NULLS_EQUAL } enum_mi_stats_method; typedef struct st_mi_check_param { ulonglong auto_increment_value; Loading Loading @@ -341,6 +355,7 @@ typedef struct st_mi_check_param void *thd; char *db_name,*table_name; char *op_name; enum_mi_stats_method stats_method; } MI_CHECK; typedef struct st_sort_ft_buf Loading myisam/mi_check.c +17 −13 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ void myisamchk_init(MI_CHECK *param) param->start_check_pos=0; param->max_record_length= LONGLONG_MAX; param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE; param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; } /* Check the status flags for the table */ Loading Loading @@ -558,10 +559,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, ha_checksum *key_checksum, uint level) { int flag; uint used_length,comp_flag,nod_flag,key_length=0,not_used; uint used_length,comp_flag,nod_flag,key_length=0; uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos; my_off_t next_page,record; char llbuff[22]; uint diff_pos; DBUG_ENTER("chk_index"); DBUG_DUMP("buff",(byte*) buff,mi_getint(buff)); Loading Loading @@ -619,7 +621,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, } if ((*keys)++ && (flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length, comp_flag, ¬_used)) >=0) comp_flag, &diff_pos)) >=0) { DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length); DBUG_DUMP("new",(byte*) key, key_length); Loading @@ -635,11 +637,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, { if (*keys != 1L) /* not first_key */ { uint diff; if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff); param->unique_count[diff-1]++; &diff_pos); param->unique_count[diff_pos-1]++; } } (*key_checksum)+= mi_byte_checksum((byte*) key, Loading Loading @@ -3249,9 +3251,10 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE, &diff_pos); if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos); (uchar*) a, USE_WHOLE_KEY, SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos); sort_param->unique[diff_pos-1]++; } else Loading Loading @@ -3989,9 +3992,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, unique[0]= (#different values of {keypart1}) - 1 unique[1]= (#different values of {keypart2,keypart1} tuple) - unique[0] - 1 ... Here we assume that NULL != NULL (see SEARCH_NULL_ARE_NOT_EQUAL). The 'unique' array is collected in one sequential scan through the entire The 'unique' array is collected in one sequential scan through the entire index. This is done in two places: in chk_index() and in sort_key_write(). Statistics collection may consider NULLs as either equal or inequal (see SEARCH_NULL_ARE_NOT_EQUAL, MI_STATS_METHOD_*). Output is an array: rec_per_key_part[k] = Loading myisam/myisamchk.c +26 −1 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ static const char *field_pack[]= "no zeros", "blob", "constant", "table-lockup", "always zero","varchar","unique-hash","?","?"}; static const char *myisam_stats_method_str="nulls_inequal"; static void get_options(int *argc,char * * *argv); static void print_version(void); Loading Loading @@ -155,7 +156,7 @@ enum options_mc { OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE, OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN, OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE, OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD }; static struct my_option my_long_options[] = Loading Loading @@ -336,6 +337,11 @@ static struct my_option my_long_options[] = "Use stopwords from this file instead of built-in list.", (gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"stats_method", OPT_STATS_METHOD, "Specifies how index statistics collection code should threat NULLs. " "Possible values of name are \"nulls_inequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).", (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; Loading Loading @@ -465,6 +471,12 @@ static void usage(void) #include <help_end.h> const char *myisam_stats_method_names[] = {"nulls_inequal", "nulls_equal", NullS}; TYPELIB myisam_stats_method_typelib= { array_elements(myisam_stats_method_names) - 1, "", myisam_stats_method_names, NULL}; /* Read options */ static my_bool Loading Loading @@ -684,6 +696,19 @@ get_one_option(int optid, else check_param.testflag|= T_CALC_CHECKSUM; break; case OPT_STATS_METHOD: { myisam_stats_method_str= argument; int method; if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0) { fprintf(stderr, "Invalid value of stats_method: %s.\n", argument); exit(1); } check_param.stats_method= test(method-1)? MI_STATS_METHOD_NULLS_EQUAL : MI_STATS_METHOD_NULLS_NOT_EQUAL; break; } #ifdef DEBUG /* Only useful if debugging */ case OPT_START_CHECK_POS: check_param.start_check_pos= strtoull(argument, NULL, 0); Loading mysql-test/r/myisam.result +61 −0 Original line number Diff line number Diff line Loading @@ -609,3 +609,64 @@ checksum table t2; Table Checksum test.t2 984116287 drop table t1, t2; show variables like 'myisam_stats_method'; Variable_name Value myisam_stats_method nulls_inequal create table t1 (a int, key(a)); insert into t1 values (0),(1),(2),(3),(4); insert into t1 select NULL from t1; analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE insert into t1 values (11); delete from t1 where a=11; check table t1; Table Op Msg_type Msg_text test.t1 check status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE set myisam_stats_method=nulls_equal; show variables like 'myisam_stats_method'; Variable_name Value myisam_stats_method nulls_equal insert into t1 values (11); delete from t1 where a=11; analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 5 NULL NULL YES BTREE insert into t1 values (11); delete from t1 where a=11; check table t1; Table Op Msg_type Msg_text test.t1 check status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 5 NULL NULL YES BTREE set myisam_stats_method=DEFAULT; show variables like 'myisam_stats_method'; Variable_name Value myisam_stats_method nulls_inequal insert into t1 values (11); delete from t1 where a=11; analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE insert into t1 values (11); delete from t1 where a=11; check table t1; Table Op Msg_type Msg_text test.t1 check status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE drop table t1; mysql-test/t/myisam.test +47 −0 Original line number Diff line number Diff line Loading @@ -590,4 +590,51 @@ checksum table t1; checksum table t2; drop table t1, t2; # BUG#12232: New myisam_stats_method variable. show variables like 'myisam_stats_method'; create table t1 (a int, key(a)); insert into t1 values (0),(1),(2),(3),(4); insert into t1 select NULL from t1; # default: NULLs considered inequal analyze table t1; show index from t1; insert into t1 values (11); delete from t1 where a=11; check table t1; show index from t1; # Set nulls to be equal: set myisam_stats_method=nulls_equal; show variables like 'myisam_stats_method'; insert into t1 values (11); delete from t1 where a=11; analyze table t1; show index from t1; insert into t1 values (11); delete from t1 where a=11; check table t1; show index from t1; # Set nulls back to be equal set myisam_stats_method=DEFAULT; show variables like 'myisam_stats_method'; insert into t1 values (11); delete from t1 where a=11; analyze table t1; show index from t1; insert into t1 values (11); delete from t1 where a=11; check table t1; show index from t1; drop table t1; # End of 4.1 tests Loading
include/myisam.h +15 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,20 @@ typedef struct st_sort_key_blocks /* Used when sorting */ } SORT_KEY_BLOCKS; /* MyISAM supports several statistics collection methods. Currently statistics collection method is not stored in MyISAM file and has to be specified for each table analyze/repair operation in MI_CHECK::stats_method. */ typedef enum { /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */ MI_STATS_METHOD_NULLS_NOT_EQUAL, /* Treat NULLs as equal when collecting statistics (like 4.0 did) */ MI_STATS_METHOD_NULLS_EQUAL } enum_mi_stats_method; typedef struct st_mi_check_param { ulonglong auto_increment_value; Loading Loading @@ -341,6 +355,7 @@ typedef struct st_mi_check_param void *thd; char *db_name,*table_name; char *op_name; enum_mi_stats_method stats_method; } MI_CHECK; typedef struct st_sort_ft_buf Loading
myisam/mi_check.c +17 −13 Original line number Diff line number Diff line Loading @@ -80,6 +80,7 @@ void myisamchk_init(MI_CHECK *param) param->start_check_pos=0; param->max_record_length= LONGLONG_MAX; param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE; param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; } /* Check the status flags for the table */ Loading Loading @@ -558,10 +559,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, ha_checksum *key_checksum, uint level) { int flag; uint used_length,comp_flag,nod_flag,key_length=0,not_used; uint used_length,comp_flag,nod_flag,key_length=0; uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos; my_off_t next_page,record; char llbuff[22]; uint diff_pos; DBUG_ENTER("chk_index"); DBUG_DUMP("buff",(byte*) buff,mi_getint(buff)); Loading Loading @@ -619,7 +621,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, } if ((*keys)++ && (flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length, comp_flag, ¬_used)) >=0) comp_flag, &diff_pos)) >=0) { DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length); DBUG_DUMP("new",(byte*) key, key_length); Loading @@ -635,11 +637,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, { if (*keys != 1L) /* not first_key */ { uint diff; if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff); param->unique_count[diff-1]++; &diff_pos); param->unique_count[diff_pos-1]++; } } (*key_checksum)+= mi_byte_checksum((byte*) key, Loading Loading @@ -3249,9 +3251,10 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE, &diff_pos); if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos); (uchar*) a, USE_WHOLE_KEY, SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos); sort_param->unique[diff_pos-1]++; } else Loading Loading @@ -3989,9 +3992,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, unique[0]= (#different values of {keypart1}) - 1 unique[1]= (#different values of {keypart2,keypart1} tuple) - unique[0] - 1 ... Here we assume that NULL != NULL (see SEARCH_NULL_ARE_NOT_EQUAL). The 'unique' array is collected in one sequential scan through the entire The 'unique' array is collected in one sequential scan through the entire index. This is done in two places: in chk_index() and in sort_key_write(). Statistics collection may consider NULLs as either equal or inequal (see SEARCH_NULL_ARE_NOT_EQUAL, MI_STATS_METHOD_*). Output is an array: rec_per_key_part[k] = Loading
myisam/myisamchk.c +26 −1 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ static const char *field_pack[]= "no zeros", "blob", "constant", "table-lockup", "always zero","varchar","unique-hash","?","?"}; static const char *myisam_stats_method_str="nulls_inequal"; static void get_options(int *argc,char * * *argv); static void print_version(void); Loading Loading @@ -155,7 +156,7 @@ enum options_mc { OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE, OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN, OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE, OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD }; static struct my_option my_long_options[] = Loading Loading @@ -336,6 +337,11 @@ static struct my_option my_long_options[] = "Use stopwords from this file instead of built-in list.", (gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"stats_method", OPT_STATS_METHOD, "Specifies how index statistics collection code should threat NULLs. " "Possible values of name are \"nulls_inequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).", (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; Loading Loading @@ -465,6 +471,12 @@ static void usage(void) #include <help_end.h> const char *myisam_stats_method_names[] = {"nulls_inequal", "nulls_equal", NullS}; TYPELIB myisam_stats_method_typelib= { array_elements(myisam_stats_method_names) - 1, "", myisam_stats_method_names, NULL}; /* Read options */ static my_bool Loading Loading @@ -684,6 +696,19 @@ get_one_option(int optid, else check_param.testflag|= T_CALC_CHECKSUM; break; case OPT_STATS_METHOD: { myisam_stats_method_str= argument; int method; if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0) { fprintf(stderr, "Invalid value of stats_method: %s.\n", argument); exit(1); } check_param.stats_method= test(method-1)? MI_STATS_METHOD_NULLS_EQUAL : MI_STATS_METHOD_NULLS_NOT_EQUAL; break; } #ifdef DEBUG /* Only useful if debugging */ case OPT_START_CHECK_POS: check_param.start_check_pos= strtoull(argument, NULL, 0); Loading
mysql-test/r/myisam.result +61 −0 Original line number Diff line number Diff line Loading @@ -609,3 +609,64 @@ checksum table t2; Table Checksum test.t2 984116287 drop table t1, t2; show variables like 'myisam_stats_method'; Variable_name Value myisam_stats_method nulls_inequal create table t1 (a int, key(a)); insert into t1 values (0),(1),(2),(3),(4); insert into t1 select NULL from t1; analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE insert into t1 values (11); delete from t1 where a=11; check table t1; Table Op Msg_type Msg_text test.t1 check status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE set myisam_stats_method=nulls_equal; show variables like 'myisam_stats_method'; Variable_name Value myisam_stats_method nulls_equal insert into t1 values (11); delete from t1 where a=11; analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 5 NULL NULL YES BTREE insert into t1 values (11); delete from t1 where a=11; check table t1; Table Op Msg_type Msg_text test.t1 check status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 5 NULL NULL YES BTREE set myisam_stats_method=DEFAULT; show variables like 'myisam_stats_method'; Variable_name Value myisam_stats_method nulls_inequal insert into t1 values (11); delete from t1 where a=11; analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE insert into t1 values (11); delete from t1 where a=11; check table t1; Table Op Msg_type Msg_text test.t1 check status OK show index from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A 10 NULL NULL YES BTREE drop table t1;
mysql-test/t/myisam.test +47 −0 Original line number Diff line number Diff line Loading @@ -590,4 +590,51 @@ checksum table t1; checksum table t2; drop table t1, t2; # BUG#12232: New myisam_stats_method variable. show variables like 'myisam_stats_method'; create table t1 (a int, key(a)); insert into t1 values (0),(1),(2),(3),(4); insert into t1 select NULL from t1; # default: NULLs considered inequal analyze table t1; show index from t1; insert into t1 values (11); delete from t1 where a=11; check table t1; show index from t1; # Set nulls to be equal: set myisam_stats_method=nulls_equal; show variables like 'myisam_stats_method'; insert into t1 values (11); delete from t1 where a=11; analyze table t1; show index from t1; insert into t1 values (11); delete from t1 where a=11; check table t1; show index from t1; # Set nulls back to be equal set myisam_stats_method=DEFAULT; show variables like 'myisam_stats_method'; insert into t1 values (11); delete from t1 where a=11; analyze table t1; show index from t1; insert into t1 values (11); delete from t1 where a=11; check table t1; show index from t1; drop table t1; # End of 4.1 tests