diff options
-rw-r--r-- | VC++Files/mysys/mysys.dsp | 4 | ||||
-rw-r--r-- | VC++Files/mysys/mysys_ia64.dsp | 4 | ||||
-rw-r--r-- | client/mysql.cc | 31 | ||||
-rw-r--r-- | include/my_sys.h | 3 | ||||
-rw-r--r-- | include/myisam.h | 15 | ||||
-rw-r--r-- | myisam/mi_check.c | 30 | ||||
-rw-r--r-- | myisam/myisamchk.c | 27 | ||||
-rwxr-xr-x | mysql-test/mysql-test-run.pl | 20 | ||||
-rw-r--r-- | mysql-test/r/innodb.result | 9 | ||||
-rw-r--r-- | mysql-test/r/myisam.result | 61 | ||||
-rw-r--r-- | mysql-test/t/innodb.test | 9 | ||||
-rw-r--r-- | mysql-test/t/myisam.test | 54 | ||||
-rw-r--r-- | mysys/my_conio.c | 217 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 9 | ||||
-rw-r--r-- | sql/handler.h | 1 | ||||
-rw-r--r-- | sql/mysqld.cc | 24 | ||||
-rw-r--r-- | sql/set_var.cc | 10 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_load.cc | 7 |
19 files changed, 508 insertions, 28 deletions
diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp index 230c2221b6e..935f1411530 100644 --- a/VC++Files/mysys/mysys.dsp +++ b/VC++Files/mysys/mysys.dsp @@ -369,6 +369,10 @@ SOURCE=.\my_compress.c # End Source File # Begin Source File +SOURCE=.\my_conio.c +# End Source File +# Begin Source File + SOURCE=.\my_copy.c # End Source File # Begin Source File diff --git a/VC++Files/mysys/mysys_ia64.dsp b/VC++Files/mysys/mysys_ia64.dsp index b0ce2b4c579..10d6ca7960a 100644 --- a/VC++Files/mysys/mysys_ia64.dsp +++ b/VC++Files/mysys/mysys_ia64.dsp @@ -362,6 +362,10 @@ SOURCE=.\my_compress.c # End Source File # Begin Source File +SOURCE=.\my_conio.c +# End Source File +# Begin Source File + SOURCE=.\my_copy.c # End Source File # Begin Source File diff --git a/client/mysql.cc b/client/mysql.cc index f4361f77f4c..05dfcbeccba 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -959,10 +959,15 @@ static int get_options(int argc, char **argv) static int read_and_execute(bool interactive) { -#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) +#if defined(OS2) || defined(__NETWARE__) char linebuffer[254]; String buffer; #endif +#if defined(__WIN__) + String tmpbuf; + String buffer; +#endif + char *line; char in_string=0; ulong line_number=0; @@ -993,7 +998,7 @@ static int read_and_execute(bool interactive) #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) tee_fputs(prompt, stdout); -#ifdef __NETWARE__ +#if defined(__NETWARE__) line=fgets(linebuffer, sizeof(linebuffer)-1, stdin); /* Remove the '\n' */ if (line) @@ -1002,7 +1007,22 @@ static int read_and_execute(bool interactive) if (p != NULL) *p = '\0'; } -#else +#elif defined(__WIN__) + if (!tmpbuf.is_alloced()) + tmpbuf.alloc(65535); + buffer.length(0); + unsigned long clen; + do + { + line= my_cgets(tmpbuf.c_ptr(), tmpbuf.alloced_length(), &clen); + buffer.append(line, clen); + /* + if we got buffer fully filled than there is a chance that + something else is still in console input buffer + */ + } while (tmpbuf.alloced_length() <= clen + 1); + line= buffer.c_ptr(); +#else /* OS2 */ buffer.length(0); /* _cgets() expects the buffer size - 3 as the first byte */ linebuffer[0]= (char) sizeof(linebuffer) - 3; @@ -1078,9 +1098,14 @@ static int read_and_execute(bool interactive) status.exit_status=0; } } + #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) buffer.free(); #endif +#if defined( __WIN__) + tmpbuf.free(); +#endif + return status.exit_status; } diff --git a/include/my_sys.h b/include/my_sys.h index 836b2a85528..2970f68805b 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -887,6 +887,9 @@ int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror, void my_security_attr_free(SECURITY_ATTRIBUTES *sa); +/* implemented in my_conio.c */ +char* my_cgets(char *string, unsigned long clen, unsigned long* plen); + #endif #ifdef __NETWARE__ void netware_reg_user(const char *ip, const char *user, diff --git a/include/myisam.h b/include/myisam.h index 03194fe42ae..6cc219de6e8 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -381,6 +381,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=1, + /* 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; @@ -411,6 +425,7 @@ typedef struct st_mi_check_param void *thd; const char *db_name, *table_name; const char *op_name; + enum_mi_stats_method stats_method; } MI_CHECK; typedef struct st_sort_ft_buf diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ee64f9b9979..1f453278eea 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -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 */ @@ -559,10 +560,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)); @@ -620,7 +622,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); @@ -636,11 +638,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, { if (*keys != 1L) /* not first_key */ { - uint diff; - ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, - SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, - &diff); - param->unique_count[diff-1]++; + 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_pos); + param->unique_count[diff_pos-1]++; } } (*key_checksum)+= mi_byte_checksum((byte*) key, @@ -2014,7 +2016,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, sort_param.sort_info=&sort_info; sort_param.fix_datafile= (my_bool) (! rep_quick); sort_param.master =1; - + del=info->state->del; param->glob_crc=0; if (param->testflag & T_CALC_CHECKSUM) @@ -3250,9 +3252,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); - 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); + 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); sort_param->unique[diff_pos-1]++; } else @@ -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] = diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 78ae756bf7c..cfc3930779f 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -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); @@ -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[] = @@ -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} }; @@ -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 @@ -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); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0343c19036d..2dda1b2a6e1 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2450,11 +2450,6 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--big-test"); } - if ( $opt_record ) - { - mtr_add_arg($args, "--record"); - } - if ( $opt_compress ) { mtr_add_arg($args, "--compress"); @@ -2480,9 +2475,6 @@ sub run_mysqltest ($) { $glob_mysql_test_dir); } - mtr_add_arg($args, "-R"); - mtr_add_arg($args, $tinfo->{'result_file'}); - # ---------------------------------------------------------------------- # If embedded server, we create server args to give mysqltest to pass on # ---------------------------------------------------------------------- @@ -2497,6 +2489,18 @@ sub run_mysqltest ($) { # ---------------------------------------------------------------------- $ENV{'MYSQL_TEST'}= "$exe_mysqltest " . join(" ", @$args); + # ---------------------------------------------------------------------- + # Add args that should not go into the MYSQL_TEST environment var + # ---------------------------------------------------------------------- + + mtr_add_arg($args, "-R"); + mtr_add_arg($args, $tinfo->{'result_file'}); + + if ( $opt_record ) + { + mtr_add_arg($args, "--record"); + } + return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,""); } diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 559e88aad46..4dd1d694401 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1730,6 +1730,15 @@ explain select * from t1 order by a,b,c,d; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort drop table t1; +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +min(a) +4 +select min(b) from t1 where a='8'; +min(b) +6 +drop table t1; create table t1 (x bigint unsigned not null primary key) engine=innodb; insert into t1(x) values (0xfffffffffffffff0),(0xfffffffffffffff1); select * from t1; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index ce215d6a7d8..99f84f0a67b 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -608,6 +608,67 @@ 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; set storage_engine=MyISAM; drop table if exists t1,t2,t3; --- Testing varchar --- diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index beec3b0f8c7..94f33738c8c 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1259,6 +1259,15 @@ select * from t1 order by a,b,c,d; explain select * from t1 order by a,b,c,d; drop table t1; +# +# BUG#11039,#13218 Wrong key length in min() +# + +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +select min(b) from t1 where a='8'; +drop table t1; # End of 4.1 tests # diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index eeac2971788..73afcab5e27 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -578,6 +578,59 @@ checksum table t1; # The above should give the same number as the following. 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 + # # Test varchar # @@ -700,4 +753,3 @@ create table t3 (c1 int) engine=myisam pack_keys=default; create table t4 (c1 int) engine=myisam pack_keys=2; drop table t1, t2, t3; -# End of 4.1 tests diff --git a/mysys/my_conio.c b/mysys/my_conio.c new file mode 100644 index 00000000000..e381f9f23ef --- /dev/null +++ b/mysys/my_conio.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include "mysys_priv.h" + +#ifdef __WIN__ + +static HANDLE my_coninpfh= 0; /* console input */ + +/* + functions my_pthread_auto_mutex_lock & my_pthread_auto_mutex_free + are experimental at this moment, they are intended to bring + ability of protecting code sections without necessity to explicitly + initialize synchronization object in one of threads + + if found useful they are to be exported in mysys +*/ + +/* + int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, + int id, int time) + + NOTES + creates a mutex with given name and tries to lock it time msec. + mutex name is appended with id to allow system wide or process wide + locks. Handle to created mutex returned in ph argument. + + RETURN + 0 thread owns mutex + <>0 error + +*/ +static +int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time) +{ + int res; + char tname[FN_REFLEN]; + + sprintf(tname, "%s-%08X", name, id); + + *ph= CreateMutex(NULL, FALSE, tname); + if (*ph == NULL) + return GetLastError(); + + res= WaitForSingleObject(*ph, time); + + if (res == WAIT_TIMEOUT) + return ERROR_SEM_TIMEOUT; + + if (res == WAIT_FAILED) + return GetLastError(); + + return 0; +} + +/* + int my_pthread_auto_mutex_free(HANDLE* ph) + + + NOTES + releases a mutex. + + RETURN + 0 thread released mutex + <>0 error + +*/ +static +int my_pthread_auto_mutex_free(HANDLE* ph) +{ + if (*ph) + { + ReleaseMutex(*ph); + CloseHandle(*ph); + *ph= NULL; + } + + return 0; +} + + +#define pthread_auto_mutex_decl(name) \ + HANDLE __h##name= NULL; + +#define pthread_auto_mutex_lock(name, proc, time) \ + my_pthread_auto_mutex_lock(&__h##name, #name, (proc), (time)) + +#define pthread_auto_mutex_free(name) \ + my_pthread_auto_mutex_free(&__h##name) + + +/* + char* my_cgets(char *string, unsigned long clen, unsigned long* plen) + + NOTES + Replaces _cgets from libc to support input of more than 255 chars. + Reads from the console via ReadConsole into buffer which + should be at least clen characters. + Actual length of string returned in plen. + + WARNING + my_cgets() does NOT check the pushback character buffer (i.e., _chbuf). + Thus, my_cgets() will not return any character that is pushed back by + the _ungetch() call. + + RETURN + string pointer ok + NULL Error + +*/ +char* my_cgets(char *buffer, unsigned long clen, unsigned long* plen) +{ + ULONG state; + char *result; + CONSOLE_SCREEN_BUFFER_INFO csbi; + + pthread_auto_mutex_decl(my_conio_cs); + + /* lock the console for the current process*/ + if (pthread_auto_mutex_lock(my_conio_cs, GetCurrentProcessId(), INFINITE)) + { + /* can not lock console */ + pthread_auto_mutex_free(my_conio_cs); + return NULL; + } + + /* init console input */ + if (my_coninpfh == 0) + { + /* same handle will be used until process termination */ + my_coninpfh= CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + } + + if (my_coninpfh == INVALID_HANDLE_VALUE) + { + /* unlock the console */ + pthread_auto_mutex_free(my_conio_cs); + return(NULL); + } + + GetConsoleMode((HANDLE)my_coninpfh, &state); + SetConsoleMode((HANDLE)my_coninpfh, ENABLE_LINE_INPUT | + ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT); + + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + + /* + there is no known way to determine allowed buffer size for input + though it is known it should not be more than 64K + so we cut 64K and try first size of screen buffer + if it is still to large we cut half of it and try again + later we may want to cycle from min(clen, 65535) to allowed size + with small decrement to determine exact allowed buffer + */ + clen= min(clen, 65535); + do + { + clen= min(clen, (unsigned long)csbi.dwSize.X*csbi.dwSize.Y); + if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, clen - 1, plen, NULL)) + { + result= NULL; + clen>>= 1; + } + else + { + result= buffer; + break; + } + } + while (GetLastError() == ERROR_NOT_ENOUGH_MEMORY); + + + if (result != NULL) + { + if (buffer[*plen - 2] == '\r') + { + *plen= *plen - 2; + } + else + { + if (buffer[*plen - 1] == '\r') + { + char tmp[3]; + int tmplen= sizeof(tmp); + + *plen= *plen - 1; + /* read /n left in the buffer */ + ReadConsole((HANDLE)my_coninpfh, (LPVOID)tmp, tmplen, &tmplen, NULL); + } + } + buffer[*plen]= '\0'; + } + + SetConsoleMode((HANDLE)my_coninpfh, state); + /* unlock the console */ + pthread_auto_mutex_free(my_conio_cs); + + return result; +} + +#endif /* __WIN__ */ diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 8f3970d69e6..b680c739958 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -39,6 +39,12 @@ const char *myisam_recover_names[] = TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", myisam_recover_names, NULL}; +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}; + /***************************************************************************** ** MyISAM tables @@ -324,6 +330,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) param.db_name= table->s->db; param.table_name= table->alias; param.testflag = check_opt->flags | T_CHECK | T_SILENT; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; if (!(table->db_stat & HA_READ_ONLY)) param.testflag|= T_STATISTICS; @@ -413,6 +420,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt) param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS | T_DONT_CHECK_CHECKSUM); param.using_global_keycache = 1; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; if (!(share->state.changed & STATE_NOT_ANALYZED)) return HA_ADMIN_ALREADY_DONE; @@ -967,6 +975,7 @@ int ha_myisam::enable_indexes(uint mode) T_CREATE_MISSING_KEYS); param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; param.tmpdir=&mysql_tmpdir_list; if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair) { diff --git a/sql/handler.h b/sql/handler.h index f1f9ab904d1..b61683c59b9 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -825,6 +825,7 @@ public: extern struct show_table_type_st sys_table_types[]; extern const char *ha_row_type[]; extern TYPELIB tx_isolation_typelib; +extern TYPELIB myisam_stats_method_typelib; extern handlerton *handlertons[MAX_HA]; extern ulong total_ha, total_ha_2pc; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a28ae38c675..ad2b6c5fd68 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -432,6 +432,7 @@ char server_version[SERVER_VERSION_LENGTH]; char *mysqld_unix_port, *opt_mysql_tmpdir; const char **errmesg; /* Error messages */ const char *myisam_recover_options_str="OFF"; +const char *myisam_stats_method_str="nulls_inequal"; /* name of reference on left espression in rewritten IN subquery */ const char *in_left_expr_name= "<left expr>"; /* name of additional condition */ @@ -4358,6 +4359,7 @@ enum options_mysqld OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, + OPT_MYISAM_STATS_METHOD, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT, OPT_OPEN_FILES_LIMIT, @@ -5513,6 +5515,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.myisam_sort_buff_size, (gptr*) &max_system_variables.myisam_sort_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0}, + {"myisam_stats_method", OPT_MYISAM_STATS_METHOD, + "Specifies how MyISAM 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}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "Buffer length for TCP/IP and socket communication.", (gptr*) &global_system_variables.net_buffer_length, @@ -6096,6 +6103,7 @@ static void mysql_init_variables(void) query_id= thread_id= 1L; strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; + myisam_stats_method_str= "nulls_inequal"; my_bind_addr = htonl(INADDR_ANY); threads.empty(); thread_cache.empty(); @@ -6144,6 +6152,12 @@ static void mysql_init_variables(void) global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; + + /* + Default behavior for 4.1 and 5.0 is to treat NULL values as inequal + when collecting index statistics for MyISAM tables. + */ + global_system_variables.myisam_stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; /* Variables that depends on compile options */ #ifndef DBUG_OFF @@ -6753,6 +6767,16 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), fprintf(stderr, "Unknown option to tc-heuristic-recover: %s\n",argument); exit(1); } + case OPT_MYISAM_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 myisam_stats_method: %s.\n", argument); + exit(1); + } + global_system_variables.myisam_stats_method= method; break; } case OPT_SQL_MODE: diff --git a/sql/set_var.cc b/sql/set_var.cc index ff997158941..ebd278c60f0 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -270,6 +270,12 @@ sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size", sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1); sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads); sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size); + +sys_var_thd_enum sys_myisam_stats_method("myisam_stats_method", + &SV::myisam_stats_method, + &myisam_stats_method_typelib, + NULL); + sys_var_thd_ulong sys_net_buffer_length("net_buffer_length", &SV::net_buffer_length); sys_var_thd_ulong sys_net_read_timeout("net_read_timeout", @@ -630,6 +636,7 @@ sys_var *sys_variables[]= &sys_myisam_max_sort_file_size, &sys_myisam_repair_threads, &sys_myisam_sort_buffer_size, + &sys_myisam_stats_method, &sys_net_buffer_length, &sys_net_read_timeout, &sys_net_retry_count, @@ -896,6 +903,9 @@ struct show_var_st init_vars[]= { {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads, SHOW_SYS}, {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, + + {sys_myisam_stats_method.name, (char*) &sys_myisam_stats_method, SHOW_SYS}, + #ifdef __NT__ {"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL}, #endif diff --git a/sql/sql_class.h b/sql/sql_class.h index 1a215d39841..b3eb371b4e8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -509,6 +509,7 @@ struct system_variables ulong multi_range_count; ulong myisam_repair_threads; ulong myisam_sort_buff_size; + ulong myisam_stats_method; ulong net_buffer_length; ulong net_interactive_timeout; ulong net_read_timeout; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index e1684f9bb11..fadc31f7aee 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -147,6 +147,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, MYF(0)); DBUG_RETURN(TRUE); } + /* + This needs to be done before external_lock + */ + ha_enable_transaction(thd, FALSE); if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); if (setup_tables(thd, &thd->lex->select_lex.context, @@ -352,7 +356,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (ignore || handle_duplicates == DUP_REPLACE) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - ha_enable_transaction(thd, FALSE); table->file->start_bulk_insert((ha_rows) 0); table->copy_blobs=1; @@ -372,10 +375,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, *enclosed, skip_lines, ignore); if (table->file->end_bulk_insert()) error=1; /* purecov: inspected */ - ha_enable_transaction(thd, TRUE); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->next_number_field=0; } + ha_enable_transaction(thd, TRUE); if (file >= 0) my_close(file,MYF(0)); free_blobs(table); /* if pack_blob was used */ |