summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VC++Files/mysys/mysys.dsp4
-rw-r--r--VC++Files/mysys/mysys_ia64.dsp4
-rw-r--r--client/mysql.cc31
-rw-r--r--include/my_sys.h3
-rw-r--r--include/myisam.h15
-rw-r--r--myisam/mi_check.c30
-rw-r--r--myisam/myisamchk.c27
-rwxr-xr-xmysql-test/mysql-test-run.pl20
-rw-r--r--mysql-test/r/innodb.result9
-rw-r--r--mysql-test/r/myisam.result61
-rw-r--r--mysql-test/t/innodb.test9
-rw-r--r--mysql-test/t/myisam.test54
-rw-r--r--mysys/my_conio.c217
-rw-r--r--sql/ha_myisam.cc9
-rw-r--r--sql/handler.h1
-rw-r--r--sql/mysqld.cc24
-rw-r--r--sql/set_var.cc10
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_load.cc7
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, &not_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 */