diff options
author | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2011-02-09 11:27:31 +0200 |
---|---|---|
committer | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2011-02-09 11:27:31 +0200 |
commit | 74fef12722a5157e5379b4a3aaf305a6f3242116 (patch) | |
tree | ff6a9d48169d40cb866403c1157f0f00ed4340de | |
parent | 9c25613afae826c24d75693723fc09bf29173692 (diff) | |
parent | 9a044cc240bbccb713faacb65e40559e2100acce (diff) | |
download | mariadb-git-74fef12722a5157e5379b4a3aaf305a6f3242116.tar.gz |
weave merge mysql-5.5->mysql-5.5-security
158 files changed, 2968 insertions, 974 deletions
@@ -5,7 +5,7 @@ For the avoidance of doubt, this particular copy of the software is released under the version 2 of the GNU General Public License.
MySQL is brought to you by the MySQL team at Oracle.
-Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
License information can be found in the COPYING file.
diff --git a/client/my_readline.h b/client/my_readline.h index 08cff565819..276e279f43d 100644 --- a/client/my_readline.h +++ b/client/my_readline.h @@ -28,11 +28,13 @@ typedef struct st_line_buffer uint eof; ulong max_size; ulong read_length; /* Length of last read string */ + int error; + bool truncated; } LINE_BUFFER; extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file); extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, char * str); -extern char *batch_readline(LINE_BUFFER *buffer, bool *truncated); +extern char *batch_readline(LINE_BUFFER *buffer); extern void batch_readline_end(LINE_BUFFER *buffer); #endif /* CLIENT_MY_READLINE_INCLUDED */ diff --git a/client/mysql.cc b/client/mysql.cc index 8fea1b054f3..5f33cad6dba 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1127,6 +1127,8 @@ int main(int argc,char *argv[]) if (status.batch && !status.line_buff && !(status.line_buff= batch_readline_init(MAX_BATCH_BUFFER_SIZE, stdin))) { + put_info("Can't initialize batch_readline - may be the input source is " + "a directory or a block device.", INFO_ERROR, 0); free_defaults(defaults_argv); my_end(0); exit(1); @@ -1839,14 +1841,13 @@ static int read_and_execute(bool interactive) ulong line_number=0; bool ml_comment= 0; COMMANDS *com; - bool truncated= 0; status.exit_status=1; - + for (;;) { if (!interactive) { - line=batch_readline(status.line_buff, &truncated); + line=batch_readline(status.line_buff); /* Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF. Editors like "notepad" put this marker in @@ -1909,9 +1910,13 @@ static int read_and_execute(bool interactive) if (opt_outfile && line) fprintf(OUTFILE, "%s\n", line); } - if (!line) // End of file + // End of file or system error + if (!line) { - status.exit_status=0; + if (status.line_buff && status.line_buff->error) + status.exit_status= 1; + else + status.exit_status= 0; break; } @@ -1932,7 +1937,8 @@ static int read_and_execute(bool interactive) #endif continue; } - if (add_line(glob_buffer,line,&in_string,&ml_comment, truncated)) + if (add_line(glob_buffer, line, &in_string, &ml_comment, + status.line_buff ? status.line_buff->truncated : 0)) break; } /* if in batch mode, send last query even if it doesn't end with \g or go */ diff --git a/client/readline.cc b/client/readline.cc index 5c1a9951d9b..c4bb4ab53f6 100644 --- a/client/readline.cc +++ b/client/readline.cc @@ -18,18 +18,26 @@ #include <my_global.h> #include <my_sys.h> #include <m_string.h> +#include <my_dir.h> #include "my_readline.h" static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size, ulong max_size); static bool init_line_buffer_from_string(LINE_BUFFER *buffer,char * str); static size_t fill_buffer(LINE_BUFFER *buffer); -static char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length, bool *truncated); +static char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length); LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file) { LINE_BUFFER *line_buff; + MY_STAT input_file_stat; + + if (my_fstat(fileno(file), &input_file_stat, MYF(MY_WME)) || + MY_S_ISDIR(input_file_stat.st_mode) || + MY_S_ISBLK(input_file_stat.st_mode)) + return 0; + if (!(line_buff=(LINE_BUFFER*) my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL)))) return 0; @@ -42,13 +50,12 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file) } -char *batch_readline(LINE_BUFFER *line_buff, bool *truncated) +char *batch_readline(LINE_BUFFER *line_buff) { char *pos; ulong out_length; - DBUG_ASSERT(truncated != NULL); - if (!(pos=intern_read_line(line_buff,&out_length, truncated))) + if (!(pos=intern_read_line(line_buff, &out_length))) return 0; if (out_length && pos[out_length-1] == '\n') if (--out_length && pos[out_length-1] == '\r') /* Remove '\n' */ @@ -162,7 +169,10 @@ static size_t fill_buffer(LINE_BUFFER *buffer) if (!(buffer->buffer = (char*) my_realloc(buffer->buffer, buffer->bufread+1, MYF(MY_WME | MY_FAE)))) - return (uint) -1; + { + buffer->error= my_errno; + return (size_t) -1; + } buffer->start_of_line=buffer->buffer+start_offset; buffer->end=buffer->buffer+bufbytes; } @@ -177,7 +187,10 @@ static size_t fill_buffer(LINE_BUFFER *buffer) /* Read in new stuff. */ if ((read_count= my_read(buffer->file, (uchar*) buffer->end, read_count, MYF(MY_WME))) == MY_FILE_ERROR) + { + buffer->error= my_errno; return (size_t) -1; + } DBUG_PRINT("fill_buff", ("Got %lu bytes", (ulong) read_count)); @@ -198,8 +211,7 @@ static size_t fill_buffer(LINE_BUFFER *buffer) } - -char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length, bool *truncated) +char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length) { char *pos; size_t length; @@ -214,22 +226,25 @@ char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length, bool *truncated) if (pos == buffer->end) { /* - fill_buffer() can return 0 either on EOF in which case we abort - or when the internal buffer has hit the size limit. In the latter case - return what we have read so far and signal string truncation. + fill_buffer() can return NULL on EOF (in which case we abort), + on error, or when the internal buffer has hit the size limit. + In the latter case return what we have read so far and signal + string truncation. */ - if (!(length=fill_buffer(buffer)) || length == (uint) -1) + if (!(length= fill_buffer(buffer))) { if (buffer->eof) DBUG_RETURN(0); } + else if (length == (size_t) -1) + DBUG_RETURN(NULL); else continue; pos--; /* break line here */ - *truncated= 1; + buffer->truncated= 1; } else - *truncated= 0; + buffer->truncated= 0; buffer->end_of_line=pos+1; *out_length=(ulong) (pos + 1 - buffer->eof - buffer->start_of_line); DBUG_RETURN(buffer->start_of_line); diff --git a/config.h.cmake b/config.h.cmake index 65ebd077da6..7de8f716e77 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -614,4 +614,9 @@ #define PROTOCOL_VERSION 10 +/* time_t related defines */ + +#cmakedefine SIZEOF_TIME_T @SIZEOF_TIME_T@ +#cmakedefine TIME_T_UNSIGNED @TIME_T_UNSIGNED@ + #endif diff --git a/configure.cmake b/configure.cmake index 954b60a45f6..90a01ff913c 100644 --- a/configure.cmake +++ b/configure.cmake @@ -574,6 +574,7 @@ MY_CHECK_TYPE_SIZE(uint32 UINT32) MY_CHECK_TYPE_SIZE(u_int32_t U_INT32_T) MY_CHECK_TYPE_SIZE(int64 INT64) MY_CHECK_TYPE_SIZE(uint64 UINT64) +MY_CHECK_TYPE_SIZE(time_t TIME_T) SET (CMAKE_EXTRA_INCLUDE_FILES sys/types.h) MY_CHECK_TYPE_SIZE(bool BOOL) SET(CMAKE_EXTRA_INCLUDE_FILES) @@ -593,6 +594,16 @@ ENDIF() # Code tests # +# check whether time_t is unsigned +CHECK_C_SOURCE_COMPILES(" +int main() +{ + int array[(((time_t)-1) > 0) ? 1 : -1]; + return 0; +}" +TIME_T_UNSIGNED) + + CHECK_C_SOURCE_COMPILES(" #ifdef _WIN32 #include <winsock2.h> diff --git a/include/my_pthread.h b/include/my_pthread.h index f1636cad136..b8608a97849 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/include/my_sys.h b/include/my_sys.h index 484dc684b03..fb8fa6e7a3e 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 @@ -104,7 +104,7 @@ typedef struct my_aio_result { #define ME_HOLDTANG 8 /* Don't delete last keys */ #define ME_WAITTOT 16 /* Wait for errtime secs of for a action */ #define ME_WAITTANG 32 /* Wait for a user action */ -#define ME_NOREFRESH 64 /* Dont refresh screen */ +#define ME_NOREFRESH 64 /* Write the error message to error log */ #define ME_NOINPUT 128 /* Dont use the input libary */ #define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */ #define ME_COLOUR2 ((2 << ME_HIGHBYTE)) diff --git a/include/my_time.h b/include/my_time.h index fdfe130c45f..68f9c2e739f 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -50,6 +50,19 @@ typedef long my_time_t; /* two-digit years < this are 20..; >= this are 19.. */ #define YY_PART_YEAR 70 +/* + check for valid times only if the range of time_t is greater than + the range of my_time_t +*/ +#if SIZEOF_TIME_T > 4 || defined(TIME_T_UNSIGNED) +# define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \ + ((x) <= TIMESTAMP_MAX_VALUE && \ + (x) >= TIMESTAMP_MIN_VALUE) +#else +# define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \ + ((x) >= TIMESTAMP_MIN_VALUE) +#endif + /* Flags to str_to_datetime */ #define TIME_FUZZY_DATE 1 #define TIME_DATETIME_ONLY 2 diff --git a/mysql-test/collections/default.daily b/mysql-test/collections/default.daily index 81dffff91ce..75c03d4d47b 100644 --- a/mysql-test/collections/default.daily +++ b/mysql-test/collections/default.daily @@ -1,5 +1,15 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog --skip-ndb + +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=normal --vardir=var-normal --report-features +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=row --vardir=var-row --mysqld=--binlog-format=row +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --mysqld=--binlog-format=row --ps-protocol +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-embedded --embedded +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=ps --vardir=var-ps --ps-protocol +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=ps_funcs1 --vardir=var-ps_funcs_1 --suite=funcs_1 --ps-protocol +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=funcs2 --vardir=var-funcs2 --suite=funcs_2 +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=partitions --vardir=var-parts --suite=parts +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=stress --vardir=var-stress --suite=stress +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=jp --vardir=var-jp --suite=jp +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=nist --vardir=var-nist --suite=nist +perl mysql-test-run.pl --force --timer --debug-server --parallel=auto --experimental=collections/default.experimental --comment=nist+ps --vardir=var-ps_nist --suite=nist --ps-protocol diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 0366bc7b949..1dedabe1ae1 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -8,7 +8,6 @@ funcs_1.charset_collation_1 # depends on compile-time decisions innodb.innodb_information_schema # Bug#48883 2010-05-11 alik Test "innodb_information_schema" takes fewer locks than expected main.func_math @freebsd # Bug#43020 2010-05-04 alik main.func_math fails on FreeBSD in PB2 -main.gis # Bug#52208 2010-11-24 alik gis fails on some platforms (Solaris, HP-UX, Linux) main.gis-rtree @freebsd # Bug#38965 2010-05-04 alik test cases gis-rtree, type_float, type_newdecimal fail in embedded server main.lock_multi_bug38499 # Bug#47448 2009-09-19 alik main.lock_multi_bug38499 times out sporadically main.outfile_loaddata @solaris # Bug#46895 2010-01-20 alik Test "outfile_loaddata" fails (reproducible) diff --git a/mysql-test/collections/default.weekly b/mysql-test/collections/default.weekly index ab792e14926..a1339fcf0fc 100755 --- a/mysql-test/collections/default.weekly +++ b/mysql-test/collections/default.weekly @@ -1,8 +1,7 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --comment=1st --experimental=collections/default.experimental 1st -perl mysql-test-run.pl --timer --force --parallel=auto --comment=big-tests --experimental=collections/default.experimental --vardir=var-big-tests --big-test --testcase-timeout=60 --suite-timeout=600 main.alter_table-big main.archive-big main.count_distinct3 main.create-big main.events_stress main.events_time_zone main.information_schema-big main.log_tables-big main.merge-big main.mysqlbinlog_row_big main.read_many_rows_innodb main.ssl-big main.sum_distinct-big main.type_newdecimal-big main.variables-big parts.part_supported_sql_func_innodb parts.partition_alter1_1_2_innodb parts.partition_alter1_2_innodb parts.partition_alter2_1_1_innodb parts.partition_alter2_1_2_innodb parts.partition_alter2_2_2_innodb parts.partition_alter4_innodb funcs_1.myisam_views-big -perl mysql-test-run.pl --timer --force --parallel=auto --comment=eits-tests-myisam-engine --experimental=collections/default.experimental --vardir=var-stmt-eits-tests-myisam-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=myisam -perl mysql-test-run.pl --timer --force --parallel=auto --comment=eits-rpl-binlog-row-tests-myisam-engine --experimental=collections/default.experimental --vardir=var-binlog-row-eits-tests-myisam-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=myisam --do-test=rpl --mysqld=--binlog-format=row -perl mysql-test-run.pl --timer --force --parallel=auto --comment=eits-rpl-binlog-mixed-tests-myisam-engine --experimental=collections/default.experimental --vardir=var-binlog-mixed-eits-tests-myisam-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=myisam --do-test=rpl --mysqld=--binlog-format=mixed -perl mysql-test-run.pl --timer --force --parallel=auto --comment=eits-tests-innodb-engine --experimental=collections/default.experimental --vardir=var-stmt-eits-tests-innodb-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=innodb --mysqld=--innodb -perl mysql-test-run.pl --timer --force --parallel=auto --comment=eits-rpl-binlog-row-tests-innodb-engine --experimental=collections/default.experimental --vardir=var-binlog-row-eits-tests-innodb-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=innodb --mysqld=--innodb --do-test=rpl --mysqld=--binlog-format=row -perl mysql-test-run.pl --timer --force --parallel=auto --comment=eits-rpl-binlog-mixed-tests-innodb-engine --experimental=collections/default.experimental --vardir=var-binlog-mixed-eits-tests-innodb-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=innodb --mysqld=--innodb --do-test=rpl --mysqld=--binlog-format=mixed +perl mysql-test-run.pl --timer --force --debug-server --parallel=auto --comment=big-tests --experimental=collections/default.experimental --vardir=var-big-tests --big-test --testcase-timeout=60 --suite-timeout=600 main.alter_table-big main.archive-big main.count_distinct3 main.create-big main.events_stress main.events_time_zone main.information_schema-big main.log_tables-big main.merge-big main.mysqlbinlog_row_big main.read_many_rows_innodb main.ssl-big main.sum_distinct-big main.type_newdecimal-big main.variables-big parts.part_supported_sql_func_innodb parts.partition_alter1_1_2_innodb parts.partition_alter1_2_innodb parts.partition_alter2_1_1_innodb parts.partition_alter2_1_2_innodb parts.partition_alter2_2_2_innodb parts.partition_alter4_innodb funcs_1.myisam_views-big +perl mysql-test-run.pl --timer --force --debug-server --parallel=auto --comment=eits-tests-myisam-engine --experimental=collections/default.experimental --vardir=var-stmt-eits-tests-myisam-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=myisam +perl mysql-test-run.pl --timer --force --debug-server --parallel=auto --comment=eits-rpl-binlog-row-tests-myisam-engine --experimental=collections/default.experimental --vardir=var-binlog-row-eits-tests-myisam-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=myisam --do-test=rpl --mysqld=--binlog-format=row +perl mysql-test-run.pl --timer --force --debug-server --parallel=auto --comment=eits-rpl-binlog-mixed-tests-myisam-engine --experimental=collections/default.experimental --vardir=var-binlog-mixed-eits-tests-myisam-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=myisam --do-test=rpl --mysqld=--binlog-format=mixed +perl mysql-test-run.pl --timer --force --debug-server --parallel=auto --comment=eits-tests-innodb-engine --experimental=collections/default.experimental --vardir=var-stmt-eits-tests-innodb-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=innodb --mysqld=--innodb +perl mysql-test-run.pl --timer --force --debug-server --parallel=auto --comment=eits-rpl-binlog-row-tests-innodb-engine --experimental=collections/default.experimental --vardir=var-binlog-row-eits-tests-innodb-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=innodb --mysqld=--innodb --do-test=rpl --mysqld=--binlog-format=row +perl mysql-test-run.pl --timer --force --debug-server --parallel=auto --comment=eits-rpl-binlog-mixed-tests-innodb-engine --experimental=collections/default.experimental --vardir=var-binlog-mixed-eits-tests-innodb-engine --suite=engines/iuds,engines/funcs --suite-timeout=500 --max-test-fail=0 --retry-failure=0 --mysqld=--default-storage-engine=innodb --mysqld=--innodb --do-test=rpl --mysqld=--binlog-format=mixed diff --git a/mysql-test/collections/mysql-5.1-innodb.push b/mysql-test/collections/mysql-5.1-innodb.push deleted file mode 100644 index a213706498e..00000000000 --- a/mysql-test/collections/mysql-5.1-innodb.push +++ /dev/null @@ -1,5 +0,0 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=embedded --vardir=var-emebbed --embedded --experimental=collections/default.experimental --skip-ndb -perl mysql-test-run.pl --timer --force --parallel=auto --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --suite=rpl,binlog --mysqld=--binlog-format=row --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 --experimental=collections/default.experimental --skip-ndb diff --git a/mysql-test/collections/mysql-5.5-bugteam.daily b/mysql-test/collections/mysql-5.5-bugteam.daily deleted file mode 100644 index 81dffff91ce..00000000000 --- a/mysql-test/collections/mysql-5.5-bugteam.daily +++ /dev/null @@ -1,5 +0,0 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog --skip-ndb diff --git a/mysql-test/collections/mysql-5.5-bugteam.push b/mysql-test/collections/mysql-5.5-bugteam.push deleted file mode 100644 index 06118ed9e1e..00000000000 --- a/mysql-test/collections/mysql-5.5-bugteam.push +++ /dev/null @@ -1,4 +0,0 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=main_ps_row --vardir=var-main-ps_row --suite=main --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=main_embedded --vardir=var-main_emebbed --suite=main --embedded --experimental=collections/default.experimental --skip-ndb -perl mysql-test-run.pl --timer --force --parallel=auto --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 --experimental=collections/default.experimental --skip-ndb diff --git a/mysql-test/collections/mysql-5.5-innodb.push b/mysql-test/collections/mysql-5.5-innodb.push deleted file mode 100644 index a213706498e..00000000000 --- a/mysql-test/collections/mysql-5.5-innodb.push +++ /dev/null @@ -1,5 +0,0 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=embedded --vardir=var-emebbed --embedded --experimental=collections/default.experimental --skip-ndb -perl mysql-test-run.pl --timer --force --parallel=auto --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --suite=rpl,binlog --mysqld=--binlog-format=row --experimental=collections/default.experimental --skip-ndb --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 --experimental=collections/default.experimental --skip-ndb diff --git a/mysql-test/collections/mysql-next-mr.push b/mysql-test/collections/mysql-next-mr.push deleted file mode 100644 index b87cc4b801f..00000000000 --- a/mysql-test/collections/mysql-next-mr.push +++ /dev/null @@ -1,5 +0,0 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 diff --git a/mysql-test/collections/mysql-trunk-innodb.push b/mysql-test/collections/mysql-trunk-innodb.push deleted file mode 100644 index df00743c6d8..00000000000 --- a/mysql-test/collections/mysql-trunk-innodb.push +++ /dev/null @@ -1,5 +0,0 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --suite=main,binlog,innodb,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --suite=main,binlog,innodb,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded --suite=main,binlog,innodb,rpl,sys_vars,perfschema -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 diff --git a/mysql-test/collections/mysql-trunk.push b/mysql-test/collections/mysql-trunk.push deleted file mode 100644 index b87cc4b801f..00000000000 --- a/mysql-test/collections/mysql-trunk.push +++ /dev/null @@ -1,5 +0,0 @@ -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog --skip-test-list=collections/disabled-per-push.list -perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 diff --git a/mysql-test/extra/rpl_tests/rpl_insert_duplicate.test b/mysql-test/extra/rpl_tests/rpl_insert_duplicate.test new file mode 100644 index 00000000000..a81eeba3231 --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_insert_duplicate.test @@ -0,0 +1,59 @@ +# BUG#59338 Inconsistency in binlog for statements that don't change any rows STATEMENT SBR +# In SBR, if a statement does not fail, it is always written to the binary log, +# regardless if rows are changed or not. If there is a failure, a statement is +# only written to the binary log if a non-transactional (.e.g. MyIsam) engine +# is updated. INSERT ON DUPLICATE KEY UPDATE was not following the rule above +# and was not written to the binary log, if then engine was Innodb. +# +# In this test case, we check if INSERT ON DUPLICATE KEY UPDATE that does not +# change anything is still written to the binary log. + +# Prepare environment +--connection master + +eval CREATE TABLE t1 ( + a INT UNSIGNED NOT NULL PRIMARY KEY +) ENGINE=$engine_type; + +eval CREATE TABLE t2 ( + a INT UNSIGNED +) ENGINE=$engine_type; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); + +# An insert duplicate that does not update anything must be written to the binary +# log in SBR and MIXED modes. We check this property by summing a before and after +# the update and comparing the binlog positions. The sum should be the same at both +# points and the statement should be in the binary log. +--let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1) +--let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1) +--let $statement_file=INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a +--eval $statement_file + +--let $assert_cond= SUM(a) = 1 FROM t1 +--let $assert_text= Sum of elements in t1 should be 1. +--source include/assert.inc + +if (`SELECT @@BINLOG_FORMAT = 'ROW'`) +{ + --let $binlog_position_cmp= = + --let $assert_cond= [SHOW MASTER STATUS, Position, 1] $binlog_position_cmp $binlog_start + --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. +} +if (`SELECT @@BINLOG_FORMAT != 'ROW'`) +{ + --let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 1, 1\', Info, 1]\' LIKE \'%$statement_file\' + --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. +} +--source include/assert.inc + +# Compare master and slave +--sync_slave_with_master +--let $diff_tables= master:test.t1 , slave:test.t1 +--source include/diff_tables.inc + +# Clean up +--connection master +drop table t1, t2; +--sync_slave_with_master diff --git a/mysql-test/extra/rpl_tests/rpl_insert_ignore.test b/mysql-test/extra/rpl_tests/rpl_insert_ignore.test index ee09c316354..270dde7675c 100644 --- a/mysql-test/extra/rpl_tests/rpl_insert_ignore.test +++ b/mysql-test/extra/rpl_tests/rpl_insert_ignore.test @@ -5,6 +5,7 @@ # Slave needs to be started with --innodb to store table in InnoDB. # Same test for MyISAM (which had no bug). +--connection master eval CREATE TABLE t1 ( a int unsigned not null auto_increment primary key, b int unsigned, @@ -32,40 +33,44 @@ INSERT INTO t2 VALUES (5, 4); INSERT INTO t2 VALUES (6, 6); INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; - -# Compare results - -SELECT * FROM t1 ORDER BY a; - -sync_slave_with_master; -SELECT * FROM t1 ORDER BY a; - -# Now do the same for MyISAM - -connection master; -drop table t1; -eval CREATE TABLE t1 ( - a int unsigned not null auto_increment primary key, - b int unsigned, - unique (b) -) ENGINE=$engine_type2; - -INSERT INTO t1 VALUES (1, 1); -INSERT INTO t1 VALUES (2, 2); -INSERT INTO t1 VALUES (3, 3); -INSERT INTO t1 VALUES (4, 4); - ---disable_warnings -INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; ---enable_warnings - -SELECT * FROM t1 ORDER BY a; - -sync_slave_with_master; -SELECT * FROM t1 ORDER BY a; - -connection master; +--let $assert_cond= COUNT(*) = 6 FROM t1 +--let $assert_text= Count of elements in t1 should be 6. +--source include/assert.inc + +# Compare master and slave +--sync_slave_with_master +--let $diff_tables= master:test.t1 , slave:test.t1 +--source include/diff_tables.inc + +# BUG#59338 Inconsistency in binlog for statements that don't change any rows STATEMENT SBR +# An insert ignore that does not update anything must be written to the binary log in SBR +# and MIXED modes. We check this property by counting occurrences in t1 before and after +# the insert and comparing the binlog positions. The count should be the same in both points +# and the statement should be in the binary log. +--connection master +--let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1) +--let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1) +--let $statement_file=INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a +--eval $statement_file + +--let $assert_cond= COUNT(*) = 6 FROM t1 +--let $assert_text= Count of elements in t1 should be 6. +--source include/assert.inc + +if (`SELECT @@BINLOG_FORMAT = 'ROW'`) +{ + --let $binlog_position_cmp= = + --let $assert_cond= [SHOW MASTER STATUS, Position, 1] $binlog_position_cmp $binlog_start + --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. +} +if (`SELECT @@BINLOG_FORMAT != 'ROW'`) +{ + --let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 2, 1\', Info, 1]\' LIKE \'%$statement_file\' + --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. +} +--source include/assert.inc + +# Clean up +--connection master drop table t1, t2; -sync_slave_with_master; - -# End of 4.1 tests +--sync_slave_with_master diff --git a/mysql-test/include/commit.inc b/mysql-test/include/commit.inc index 81fbdb03bca..9df1571a849 100644 --- a/mysql-test/include/commit.inc +++ b/mysql-test/include/commit.inc @@ -502,16 +502,16 @@ call p_verify_status_increment(2, 2, 2, 2); --echo # 12. Read-write statement: IODKU, change 0 rows. --echo # insert t1 set a=2 on duplicate key update a=2; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); commit; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); --echo # 13. Read-write statement: INSERT IGNORE, change 0 rows. --echo # insert ignore t1 set a=2; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); commit; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); --echo # 14. Read-write statement: INSERT IGNORE, change 1 row. --echo # diff --git a/mysql-test/include/gis_keys.inc b/mysql-test/include/gis_keys.inc index c75311f062a..ad00c7e1ef9 100644 --- a/mysql-test/include/gis_keys.inc +++ b/mysql-test/include/gis_keys.inc @@ -44,3 +44,19 @@ SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)'); DROP TABLE t1, t2; --echo End of 5.0 tests + + +--echo # +--echo # Test for bug #58650 "Failing assertion: primary_key_no == -1 || +--echo # primary_key_no == 0". +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +--echo # The minimal test case. +create table t1 (a int not null, b linestring not null, unique key b (b(12)), unique key a (a)); +drop table t1; +--echo # The original test case. +create table t1 (a int not null, b linestring not null, unique key b (b(12))); +create unique index a on t1(a); +drop table t1; diff --git a/mysql-test/include/have_dbi_dbd-mysql.inc b/mysql-test/include/have_dbi_dbd-mysql.inc new file mode 100644 index 00000000000..212e36ac353 --- /dev/null +++ b/mysql-test/include/have_dbi_dbd-mysql.inc @@ -0,0 +1,78 @@ +# +# Originally created by John Embretsen, 2011-01-26. +# +# Checks for the existence of Perl modules DBI and DBD::mysql as seen from the +# perl installation used by "external" executable perl scripts, i.e. scripts +# that are executed as standalone scripts interpreted by the perl installation +# specified by the "shebang" line in the top of these scripts. +# +# If either module is not found, the test will be skipped. +# +# For use in tests that call perl scripts that require these modules. +# +# This file is intended to work on Unix. Windows may need different treatment. +# Reasoning: +# - "shebangs" are not relevant on Windows, but need to be handled here. +# - Perl scripts cannot be made executable on Windows, interpreter must be +# specified. +# +# Note that if there are multiple perl installations and not all have the +# required modules, this check may fail even if the perl in path does have +# the modules available. This may happen if the perl specified by the script's +# shebang (e.g. #!/usr/bin/perl) does not have these modules, and script is +# called without specifying the perl interpreter. However, this will be +# a correct result in cases where a test calls a script with a similar shebang. +# +################################################################################ + +--source include/not_windows.inc + +# We jump through some hoops since there is no direct way to check if an +# external command went OK or not from a mysql-test file: +# +# - In theory, we could do as simple as "exec perl -MDBI -MDBD::mysql -e 1", +# however we cannot check the result (exit code) from within a test script. +# Also, this may not yield the same result as other uses of perl due to the +# shebang issue mentioned above. +# - Instead we use a separate helper perl script that checks for the modules. +# - If the modules are found, the perl script leaves a file which sets a +# variable that can be read by this file. +# If the modules are not found, the perl script does not set this variable, +# but leaves an empty file instead. +# +# This is done because there is apparently no direct way to transfer +# information from perl to the test script itself. + +--disable_query_log +--disable_result_log +--disable_warnings + +# We do not use embedded perl in this script because that would not have yielded +# correct results for a situation where an external Perl script is called like +# "scriptname" instead of "perl scriptname" and the shebang in the script points +# to a specific perl that may be different than the perl in PATH. +# +# Instead, we call a separate helper script which checks for the modules in its +# own environment. We call it without "perl" in front. + +--let $perlChecker= $MYSQLTEST_VARDIR/std_data/checkDBI_DBD-mysql.pl +--let $resultFile= $MYSQL_TMP_DIR/dbidbd-mysql.txt + +# Make the script executable and execute it. +--chmod 0755 $perlChecker +--exec $perlChecker + +# Source the resulting temporary file and look for a variable being set. +--source $resultFile + +if (!$dbidbd) { + --skip Test needs Perl modules DBI and DBD::mysql +} + +# Clean up +--remove_file $resultFile + +--enable_query_log +--enable_result_log +--enable_warnings + diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index f793ff54e86..78cc9882d79 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -183,9 +183,6 @@ INSERT INTO global_suppressions VALUES ("The slave I.O thread stops because a fatal error is encountered when it try to get the value of SERVER_ID variable from master."), (".SELECT UNIX_TIMESTAMP... failed on master, do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS"), - /* Test case for Bug#31590 in order_by.test produces the following error */ - ("Out of sort memory; increase server sort buffer size"), - /* Special case for Bug #26402 in show_check.test - Question marks are not valid file name parts on Windows. Ignore this error message. diff --git a/mysql-test/include/mysqlhotcopy.inc b/mysql-test/include/mysqlhotcopy.inc index 91e0eff1e0f..fcf57a68644 100644 --- a/mysql-test/include/mysqlhotcopy.inc +++ b/mysql-test/include/mysqlhotcopy.inc @@ -4,12 +4,26 @@ --source include/not_windows.inc --source include/not_embedded.inc +--source include/have_dbi_dbd-mysql.inc if (!$MYSQLHOTCOPY) { + # Fail the test if the mysqlhotcopy script is missing. + # If the tool's location changes, mysql-test-run.pl must be updated to + # reflect this (look for "MYSQLHOTCOPY"). die due to missing mysqlhotcopy tool; } +# NOTE (johnemb, 2011-01-26): +# In this test mysqlhotcopy (a perl script) is executed as a standalone +# executable, i.e. not necessarily using the perl interpreter in PATH, +# because that is how the documentation demonstrates it. +# +# We include have_dbi_dbd-mysql.inc above so that the test will +# be skipped if Perl modules required by the mysqlhotcopy tool are not +# found when the script is run this way. + + let $MYSQLD_DATADIR= `SELECT @@datadir`; --disable_warnings DROP DATABASE IF EXISTS hotcopy_test; @@ -93,7 +107,7 @@ DROP DATABASE hotcopy_save; --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR --list_files $MYSQLD_DATADIR/hotcopy_save --replace_result $MASTER_MYSOCK MASTER_MYSOCK ---error 9,2304 +--error 9,11,2304 --exec $MYSQLHOTCOPY --quiet -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save --replace_result $MASTER_MYSOCK MASTER_MYSOCK --exec $MYSQLHOTCOPY --quiet --allowold -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save diff --git a/mysql-test/include/plugin.defs b/mysql-test/include/plugin.defs index 4da03dc2cc9..e07c603c8e5 100644 --- a/mysql-test/include/plugin.defs +++ b/mysql-test/include/plugin.defs @@ -27,7 +27,7 @@ # with name1, name2 etc from the comma separated list of plugin names # in the optional 4th argument. -auth_test_plugin plugin/auth PLUGIN_AUTH test_plugin_server +auth_test_plugin plugin/auth PLUGIN_AUTH test_plugin_server,cleartext_plugin_server qa_auth_interface plugin/auth PLUGIN_AUTH_INTERFACE qa_auth_interface qa_auth_server plugin/auth PLUGIN_AUTH_SERVER qa_auth_server qa_auth_client plugin/auth PLUGIN_AUTH_CLIENT qa_auth_client diff --git a/mysql-test/include/rpl_sync.inc b/mysql-test/include/rpl_sync.inc index a05bee23981..be2904528ff 100644 --- a/mysql-test/include/rpl_sync.inc +++ b/mysql-test/include/rpl_sync.inc @@ -88,7 +88,7 @@ while ($_rpl_i) { { --echo Sync IO: $_rpl_slave_io_running; Sync SQL: $_rpl_slave_sql_running } - --let $_rpl_slave_io_running= `SELECT IF('$_rpl_slave_io_running' = 'Yes', 1, '')` + --let $_rpl_slave_io_running= `SELECT IF('$_rpl_slave_io_running' != 'No', 1, '')` --let $_rpl_slave_sql_running= `SELECT IF('$_rpl_slave_sql_running' = 'Yes', 1, '')` if ($_rpl_slave_io_running) { diff --git a/mysql-test/lib/My/SafeProcess.pm b/mysql-test/lib/My/SafeProcess.pm index f87b7b60bd6..14153982d4e 100644 --- a/mysql-test/lib/My/SafeProcess.pm +++ b/mysql-test/lib/My/SafeProcess.pm @@ -1,5 +1,5 @@ # -*- cperl -*- -# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public @@ -139,6 +139,7 @@ sub new { my $host = delete($opts{'host'}); my $shutdown = delete($opts{'shutdown'}); my $user_data= delete($opts{'user_data'}); + my $envs = delete($opts{'envs'}); # if (defined $host) { # $safe_script= "lib/My/SafeProcess/safe_process_cpcd.pl"; @@ -161,6 +162,13 @@ sub new { # Point the safe_process at the right parent if running on cygwin push(@safe_args, "--parent-pid=".Cygwin::pid_to_winpid($$)) if IS_CYGWIN; + foreach my $env_var (@$envs) { + croak("Missing = in env string") unless $env_var =~ /=/; + croak("Env string $env_var seen, probably missing value for --mysqld-env") + if $env_var =~ /^--/; + push @safe_args, "--env $env_var"; + } + push(@safe_args, "--"); push(@safe_args, $path); # The program safe_process should execute diff --git a/mysql-test/lib/My/SafeProcess/safe_process.cc b/mysql-test/lib/My/SafeProcess/safe_process.cc index 477beca0ada..e5eca0c0d8b 100644 --- a/mysql-test/lib/My/SafeProcess/safe_process.cc +++ b/mysql-test/lib/My/SafeProcess/safe_process.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 MySQL AB, 2009 Sun Microsystems, Inc. +/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. 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 @@ -175,7 +175,7 @@ int main(int argc, char* const argv[] ) } else { if ( strcmp(arg, "--verbose") == 0 ) verbose++; - else if ( strncmp(arg, "--parent-pid", 10) == 0 ) + else if ( strncmp(arg, "--parent-pid", 12) == 0 ) { /* Override parent_pid with a value provided by user */ const char* start; @@ -184,10 +184,15 @@ int main(int argc, char* const argv[] ) start++; /* Step past = */ if ((parent_pid= atoi(start)) == 0) die("Invalid value '%s' passed to --parent-id", start); - } else if ( strcmp(arg, "--nocore") == 0 ) + } + else if ( strcmp(arg, "--nocore") == 0 ) { nocore = true; // Don't allow the process to dump core } + else if ( strncmp (arg, "--env ", 6) == 0 ) + { + putenv(strdup(arg+6)); + } else die("Unknown option: %s", arg); } diff --git a/mysql-test/lib/My/SafeProcess/safe_process_win.cc b/mysql-test/lib/My/SafeProcess/safe_process_win.cc index 50e16ff25d4..7e0ae68b4de 100644 --- a/mysql-test/lib/My/SafeProcess/safe_process_win.cc +++ b/mysql-test/lib/My/SafeProcess/safe_process_win.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 MySQL AB, 2009 Sun Microsystems, Inc. +/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. 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 @@ -220,6 +220,10 @@ int main(int argc, const char** argv ) { nocore= TRUE; } + else if ( strncmp (arg, "--env ", 6) == 0 ) + { + putenv(strdup(arg+6)); + } else die("Unknown option: %s", arg); } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6b08e671545..a1e02a56164 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -176,6 +176,7 @@ our $opt_big_test= 0; our @opt_combinations; our @opt_extra_mysqld_opt; +our @opt_mysqld_envs; my $opt_compress; my $opt_ssl; @@ -190,6 +191,7 @@ my $opt_view_protocol; our $opt_debug; my $debug_d= "d"; my $opt_debug_common; +our $opt_debug_server; our @opt_cases; # The test cases names in argv our $opt_embedded_server; @@ -416,6 +418,14 @@ sub main { my $server_port = $server->sockport(); mtr_report("Using server port $server_port"); + # -------------------------------------------------------------------------- + # Read definitions from include/plugin.defs + # + read_plugin_defs("include/plugin.defs"); + + # Simplify reference to semisync plugins + $ENV{'SEMISYNC_PLUGIN_OPT'}= $ENV{'SEMISYNC_MASTER_PLUGIN_OPT'}; + # Create child processes my %children; for my $child_num (1..$opt_parallel){ @@ -962,6 +972,7 @@ sub command_line_setup { # Extra options used when starting mysqld 'mysqld=s' => \@opt_extra_mysqld_opt, + 'mysqld-env=s' => \@opt_mysqld_envs, # Run test on running server 'extern=s' => \%opts_extern, # Append to hash @@ -969,6 +980,7 @@ sub command_line_setup { # Debugging 'debug' => \$opt_debug, 'debug-common' => \$opt_debug_common, + 'debug-server' => \$opt_debug_server, 'gdb' => \$opt_gdb, 'client-gdb' => \$opt_client_gdb, 'manual-gdb' => \$opt_manual_gdb, @@ -1125,6 +1137,9 @@ sub command_line_setup { ($auth_plugin)= find_plugin("auth_test_plugin", "plugin/auth"); + # --debug[-common] implies we run debug server + $opt_debug_server= 1 if $opt_debug || $opt_debug_common; + if (using_extern()) { # Connect to the running mysqld and find out what it supports @@ -1777,7 +1792,7 @@ sub find_mysqld { my @mysqld_names= ("mysqld", "mysqld-max-nt", "mysqld-max", "mysqld-nt"); - if ( $opt_debug ){ + if ( $opt_debug_server ){ # Put mysqld-debug first in the list of binaries to look for mtr_verbose("Adding mysqld-debug first in list of binaries to look for"); unshift(@mysqld_names, "mysqld-debug"); @@ -1874,9 +1889,12 @@ sub executable_setup () { sub client_debug_arg($$) { my ($args, $client_name)= @_; + # Workaround for Bug #50627: drop any debug opt + return if $client_name =~ /^mysqlbinlog/; + if ( $opt_debug ) { mtr_add_arg($args, - "--debug=$debug_d:t:A,%s/log/%s.trace", + "--loose-debug=$debug_d:t:A,%s/log/%s.trace", $path_vardir_trace, $client_name) } } @@ -1971,7 +1989,7 @@ sub find_plugin($$) { my ($plugin, $location) = @_; my $plugin_filename; - + if (IS_WINDOWS) { $plugin_filename = $plugin.".dll"; @@ -1981,13 +1999,13 @@ sub find_plugin($$) $plugin_filename = $plugin.".so"; } - my $lib_example_plugin= + my $lib_plugin= mtr_file_exists(vs_config_dirs($location,$plugin_filename), "$basedir/lib/plugin/".$plugin_filename, "$basedir/$location/.libs/".$plugin_filename, "$basedir/lib/mysql/plugin/".$plugin_filename, ); - return $lib_example_plugin; + return $lib_plugin; } # @@ -1997,10 +2015,16 @@ sub find_plugin($$) sub read_plugin_defs($) { my ($defs_file)= @_; + my $running_debug= 0; open(PLUGDEF, '<', $defs_file) or mtr_error("Can't read plugin defintions file $defs_file"); + # Need to check if we will be running mysqld-debug + if ($opt_debug_server) { + $running_debug= 1 if find_mysqld($basedir) =~ /-debug$/; + } + while (<PLUGDEF>) { next if /^#/; my ($plug_file, $plug_loc, $plug_var, $plug_names)= split; @@ -2008,6 +2032,9 @@ sub read_plugin_defs($) next unless $plug_file; mtr_error("Lines in $defs_file must have 3 or 4 items") unless $plug_var; + # If running debug server, plugins will be in 'debug' subdirectory + $plug_file= "debug/$plug_file" if $running_debug; + my ($plugin)= find_plugin($plug_file, $plug_loc); # Set env. variables that tests may use, set to empty if plugin @@ -2072,19 +2099,10 @@ sub environment_setup { push(@ld_library_paths, "$basedir/storage/ndb/src/.libs"); } - # -------------------------------------------------------------------------- - # Read definitions from include/plugin.defs - # # Plugin settings should no longer be added here, instead # place definitions in include/plugin.defs. # See comment in that file for details. # -------------------------------------------------------------------------- - read_plugin_defs("include/plugin.defs"); - - # Simplify reference to semisync plugins - $ENV{'SEMISYNC_PLUGIN_OPT'}= $ENV{'SEMISYNC_MASTER_PLUGIN_OPT'}; - - # -------------------------------------------------------------------------- # Valgrind need to be run with debug libraries otherwise it's almost # impossible to add correct supressions, that means if "/usr/lib/debug" # is available, it should be added to @@ -2513,9 +2531,9 @@ sub check_debug_support ($) { #mtr_report(" - binaries are not debug compiled"); $debug_compiled_binaries= 0; - if ( $opt_debug ) + if ( $opt_debug_server ) { - mtr_error("Can't use --debug, binaries does not support it"); + mtr_error("Can't use --debug[-server], binary does not support it"); } return; } @@ -4720,6 +4738,7 @@ sub mysqld_start ($$) { nocore => $opt_skip_core, host => undef, shutdown => sub { mysqld_stop($mysqld) }, + envs => \@opt_mysqld_envs, ); mtr_verbose("Started $mysqld->{proc}"); } @@ -5734,9 +5753,10 @@ Options for test case authoring check-testcases Check testcases for sideeffects mark-progress Log line number and elapsed time to <testname>.progress -Options that pass on options +Options that pass on options (these may be repeated) mysqld=ARGS Specify additional arguments to "mysqld" + mysqld-env=VAR=VAL Specify additional environment settings for "mysqld" Options to run test on running server @@ -5755,6 +5775,8 @@ Options for debugging the product debug Dump trace output for all servers and client programs debug-common Same as debug, but sets 'd' debug flags to "query,info,error,enter,exit" + debug-server Use debug version of server, but without turning on + tracing debugger=NAME Start mysqld in the selected debugger gdb Start the mysqld(s) in gdb manual-debug Let user manually start mysqld in debugger, before diff --git a/mysql-test/r/commit_1innodb.result b/mysql-test/r/commit_1innodb.result index 993d33d7a38..fb1552b6c28 100644 --- a/mysql-test/r/commit_1innodb.result +++ b/mysql-test/r/commit_1innodb.result @@ -519,21 +519,21 @@ SUCCESS # 12. Read-write statement: IODKU, change 0 rows. # insert t1 set a=2 on duplicate key update a=2; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); SUCCESS commit; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); SUCCESS # 13. Read-write statement: INSERT IGNORE, change 0 rows. # insert ignore t1 set a=2; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); SUCCESS commit; -call p_verify_status_increment(1, 0, 1, 0); +call p_verify_status_increment(2, 2, 1, 0); SUCCESS # 14. Read-write statement: INSERT IGNORE, change 1 row. diff --git a/mysql-test/r/csv_not_null.result b/mysql-test/r/csv_not_null.result index af583a36837..aed9bcb1587 100644 --- a/mysql-test/r/csv_not_null.result +++ b/mysql-test/r/csv_not_null.result @@ -19,13 +19,16 @@ INSERT INTO t1 VALUES(); SELECT * FROM t1; a b c d e f 0 foo 0000-00-00 +INSERT INTO t1 VALUES(default,default,default,default,default,default); SELECT * FROM t1; a b c d e f 0 foo 0000-00-00 +0 foo 0000-00-00 INSERT INTO t1 VALUES(0,'abc','def','ghi','bar','1999-12-31'); SELECT * FROM t1; a b c d e f 0 foo 0000-00-00 +0 foo 0000-00-00 0 abc def ghi bar 1999-12-31 # === insert failures === INSERT INTO t1 VALUES(NULL,'ab','a','b','foo','2007-01-01'); diff --git a/mysql-test/r/filesort_debug.result b/mysql-test/r/filesort_debug.result new file mode 100644 index 00000000000..cb62e5e7a21 --- /dev/null +++ b/mysql-test/r/filesort_debug.result @@ -0,0 +1,16 @@ +SET @old_debug= @@session.debug; +# +# Bug#36022 please log more information about "Sort aborted" queries +# +CREATE TABLE t1(f0 int auto_increment primary key, f1 int); +INSERT INTO t1(f1) VALUES (0),(1),(2),(3),(4),(5); +SET session debug= '+d,make_char_array_fail'; +CALL mtr.add_suppression("Out of sort memory"); +SELECT * FROM t1 ORDER BY f1 ASC, f0; +ERROR HY001: Out of sort memory, consider increasing server sort buffer size +SET session debug= @old_debug; +CREATE FUNCTION f1() RETURNS INT RETURN 1; +DELETE FROM t1 ORDER BY (f1(10)) LIMIT 1; +ERROR 42000: Incorrect number of arguments for FUNCTION test.f1; expected 0, got 1 +DROP TABLE t1; +DROP FUNCTION f1; diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 1f6e01da0c9..2716a06b22f 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1739,6 +1739,16 @@ SELECT RELEASE_LOCK('aaaaaaaaaaaaaaaaa'); # End of 5.1 tests # +# Bug#52123 Assertion failed: aggregator == aggr->Aggrtype(), +# file .\item_sum.cc, line 587 +# +CREATE TABLE t1(a int, KEY(a)); +INSERT INTO t1 VALUES (1), (2); +SELECT 1 FROM t1 ORDER BY AVG(DISTINCT a); +1 +1 +DROP TABLE t1; +# # Bug#55648: Server crash on MIN/MAX on maximum time value # CREATE TABLE t1(c1 TIME NOT NULL); diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 34987530b5a..2a95b234548 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1273,6 +1273,24 @@ date_add('1000-01-01 00:00:00', interval '1.03:02:01.05' day_microsecond) select date_add('1000-01-01 00:00:00', interval '1.02' day_microsecond); date_add('1000-01-01 00:00:00', interval '1.02' day_microsecond) 1000-01-01 00:00:01.020000 +# +# Bug #52315 part 2 : utc_date() crashes when system time > year 2037 +# +SET TIMESTAMP=-147490000; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483648; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483646; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483647; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=0; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=-1; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=1; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=0; End of 5.0 tests select date_sub("0050-01-01 00:00:01",INTERVAL 2 SECOND); date_sub("0050-01-01 00:00:01",INTERVAL 2 SECOND) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 7939d01beff..5706f076c6c 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -960,6 +960,18 @@ COUNT(*) 2 DROP TABLE t1, t2; End of 5.0 tests +# +# Test for bug #58650 "Failing assertion: primary_key_no == -1 || +# primary_key_no == 0". +# +drop table if exists t1; +# The minimal test case. +create table t1 (a int not null, b linestring not null, unique key b (b(12)), unique key a (a)); +drop table t1; +# The original test case. +create table t1 (a int not null, b linestring not null, unique key b (b(12))); +create unique index a on t1(a); +drop table t1; create table `t1` (`col002` point)engine=myisam; insert into t1 values (),(),(); select min(`col002`) from t1 union select `col002` from t1; diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index ecd53003513..2320d399078 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1502,4 +1502,146 @@ WHERE 7; col_datetime_key NULL DROP TABLE BB; +# +# Bug#58490: Incorrect result in multi level OUTER JOIN +# in combination with IS NULL +# +CREATE TABLE t1 (i INT NOT NULL); +INSERT INTO t1 VALUES (0), (2),(3),(4); +CREATE TABLE t2 (i INT NOT NULL); +INSERT INTO t2 VALUES (0),(1), (3),(4); +CREATE TABLE t3 (i INT NOT NULL); +INSERT INTO t3 VALUES (0),(1),(2), (4); +CREATE TABLE t4 (i INT NOT NULL); +INSERT INTO t4 VALUES (0),(1),(2),(3) ; +SELECT * FROM +t1 LEFT JOIN +( t2 LEFT JOIN +( t3 LEFT JOIN +t4 +ON t4.i = t3.i +) +ON t3.i = t2.i +) +ON t2.i = t1.i +; +i i i i +0 0 0 0 +2 NULL NULL NULL +3 3 NULL NULL +4 4 4 NULL +SELECT * FROM +t1 LEFT JOIN +( t2 LEFT JOIN +( t3 LEFT JOIN +t4 +ON t4.i = t3.i +) +ON t3.i = t2.i +) +ON t2.i = t1.i +WHERE t4.i IS NULL; +i i i i +2 NULL NULL NULL +3 3 NULL NULL +4 4 4 NULL +SELECT * FROM +t1 LEFT JOIN +( ( t2 LEFT JOIN +t3 +ON t3.i = t2.i +) +) +ON t2.i = t1.i +WHERE t3.i IS NULL; +i i i +2 NULL NULL +3 3 NULL +SELECT * FROM +t1 LEFT JOIN +( ( t2 LEFT JOIN +t3 +ON t3.i = t2.i +) +JOIN t4 +ON t4.i=t2.i +) +ON t2.i = t1.i +WHERE t3.i IS NULL; +i i i i +2 NULL NULL NULL +3 3 NULL 3 +4 NULL NULL NULL +SELECT * FROM +t1 LEFT JOIN +( ( t2 LEFT JOIN +t3 +ON t3.i = t2.i +) +JOIN (t4 AS t4a JOIN t4 AS t4b ON t4a.i=t4b.i) +ON t4a.i=t2.i +) +ON t2.i = t1.i +WHERE t3.i IS NULL; +i i i i i +2 NULL NULL NULL NULL +3 3 NULL 3 3 +4 NULL NULL NULL NULL +SELECT * FROM +t1 LEFT JOIN +( ( t2 LEFT JOIN +t3 +ON t3.i = t2.i +) +JOIN (t4 AS t4a, t4 AS t4b) +ON t4a.i=t2.i +) +ON t2.i = t1.i +WHERE t3.i IS NULL; +i i i i i +2 NULL NULL NULL NULL +3 3 NULL 3 0 +3 3 NULL 3 1 +3 3 NULL 3 2 +3 3 NULL 3 3 +4 NULL NULL NULL NULL +DROP TABLE t1,t2,t3,t4; +# +# Bug#49322(Duplicate): Server is adding extra NULL row +# on processing a WHERE clause +# +CREATE TABLE h (pk INT NOT NULL, col_int_key INT); +INSERT INTO h VALUES (1,NULL),(4,2),(5,2),(3,4),(2,8); +CREATE TABLE m (pk INT NOT NULL, col_int_key INT); +INSERT INTO m VALUES (1,2),(2,7),(3,5),(4,7),(5,5),(6,NULL),(7,NULL),(8,9); +CREATE TABLE k (pk INT NOT NULL, col_int_key INT); +INSERT INTO k VALUES (1,9),(2,2),(3,5),(4,2),(5,7),(6,0),(7,5); +SELECT TABLE1.pk FROM k TABLE1 +RIGHT JOIN h TABLE2 ON TABLE1.col_int_key=TABLE2.col_int_key +RIGHT JOIN m TABLE4 ON TABLE2.col_int_key=TABLE4.col_int_key; +pk +2 +4 +2 +4 +NULL +NULL +NULL +NULL +NULL +NULL +NULL +SELECT TABLE1.pk FROM k TABLE1 +RIGHT JOIN h TABLE2 ON TABLE1.col_int_key=TABLE2.col_int_key +RIGHT JOIN m TABLE4 ON TABLE2.col_int_key=TABLE4.col_int_key +WHERE TABLE1.pk IS NULL; +pk +NULL +NULL +NULL +NULL +NULL +NULL +NULL +DROP TABLE h,m,k; End of 5.1 tests diff --git a/mysql-test/r/not_embedded_server.result b/mysql-test/r/not_embedded_server.result index 1f8fdb65407..eccf6151d33 100644 --- a/mysql-test/r/not_embedded_server.result +++ b/mysql-test/r/not_embedded_server.result @@ -3,6 +3,10 @@ SHOW VARIABLES like 'slave_skip_errors'; Variable_name Value slave_skip_errors OFF # +# Bug#58026: massive recursion and crash in regular expression handling +# +SELECT '1' RLIKE RPAD('1', 10000, '('); +# # WL#4284: Transactional DDL locking # # FLUSH PRIVILEGES should not implicitly unlock locked tables. diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 51c8f0cc741..f03ab28b484 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1425,8 +1425,9 @@ set session sort_buffer_size= 30000; Warnings: Warning 1292 Truncated incorrect sort_buffer_size value: '30000' set session max_sort_length= 2180; +CALL mtr.add_suppression("Out of sort memory"); select * from t1 order by b; -ERROR HY001: Out of sort memory; increase server sort buffer size +ERROR HY001: Out of sort memory, consider increasing server sort buffer size drop table t1; # # Bug #39844: Query Crash Mysql Server 5.0.67 @@ -1638,6 +1639,31 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL a 8 NULL 10 Using index; Using temporary; Using filesort 1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where DROP TABLE t1, t2; +# +# Bug #59110: Memory leak of QUICK_SELECT_I allocated memory +# and +# Bug #59308: Incorrect result for +SELECT DISTINCT <col>... ORDER BY <col> DESC + +# Use Valgrind to detect #59110! +# +CREATE TABLE t1 (a INT,KEY (a)); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +EXPLAIN SELECT DISTINCT a,1 FROM t1 WHERE a <> 1 ORDER BY a DESC; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index a a 5 NULL 10 Using where; Using index; Using filesort +SELECT DISTINCT a,1 FROM t1 WHERE a <> 1 ORDER BY a DESC; +a 1 +10 1 +9 1 +8 1 +7 1 +6 1 +5 1 +4 1 +3 1 +2 1 +DROP TABLE t1; End of 5.1 tests # # Bug #38745: MySQL 5.1 optimizer uses filesort for ORDER BY diff --git a/mysql-test/r/plugin_auth.result b/mysql-test/r/plugin_auth.result index fa6908530b7..7f26cdf447a 100644 --- a/mysql-test/r/plugin_auth.result +++ b/mysql-test/r/plugin_auth.result @@ -330,4 +330,16 @@ mysqld is alive # Executing 'mysqldump' # Executing 'mysql_upgrade' The --upgrade-system-tables option was used, databases won't be touched. +# +# Bug #59657: Move the client authentication_pam plugin into the +# server repository +# +CREATE USER uplain@localhost IDENTIFIED WITH 'cleartext_plugin_server' + AS 'cleartext_test'; +## test plugin auth +ERROR 28000: Access denied for user 'uplain'@'localhost' (using password: YES) +select USER(),CURRENT_USER(); +USER() CURRENT_USER() +uplain@localhost uplain@localhost +DROP USER uplain@localhost; End of 5.5 tests diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 62acb2a7710..d8f1f45de0c 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1666,4 +1666,105 @@ c_key c_notkey 1 1 3 3 DROP TABLE t1; +# +# Bug #57030: 'BETWEEN' evaluation is incorrect +# +CREATE TABLE t1(pk INT PRIMARY KEY, i4 INT); +CREATE UNIQUE INDEX i4_uq ON t1(i4); +INSERT INTO t1 VALUES (1,10), (2,20), (3,30); +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const i4_uq i4_uq 5 const 1 +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10; +pk i4 +1 10 +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const i4_uq i4_uq 5 const 1 +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4; +pk i4 +1 10 +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range i4_uq i4_uq 5 NULL 3 Using where +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4; +pk i4 +1 10 +2 20 +3 30 +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range i4_uq i4_uq 5 NULL 1 Using where +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10; +pk i4 +1 10 +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10; +pk i4 +1 10 +2 20 +3 30 +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11; +pk i4 +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0; +pk i4 +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0; +pk i4 +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range i4_uq i4_uq 5 NULL 2 Using where +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999; +pk i4 +1 10 +2 20 +3 30 +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30; +pk i4 +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range i4_uq i4_uq 5 NULL 1 Using where +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20'; +pk i4 +1 10 +2 20 +EXPLAIN +SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL i4_uq NULL NULL NULL 3 +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.i4 1 Using where +SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4; +pk i4 pk i4 +EXPLAIN +SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL i4_uq NULL NULL NULL 3 +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.i4 1 Using where +SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk; +pk i4 pk i4 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/ssl_and_innodb.result b/mysql-test/r/ssl_and_innodb.result new file mode 100644 index 00000000000..71373fc4033 --- /dev/null +++ b/mysql-test/r/ssl_and_innodb.result @@ -0,0 +1,8 @@ +CREATE TABLE t1(a int) engine=innodb; +INSERT INTO t1 VALUES (1); +SELECT DISTINCT +convert((SELECT des_decrypt(2,1) AS a FROM t1 WHERE @a:=1), signed) as d +FROM t1 ; +d +2 +DROP TABLE t1; diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result index 4dac7443135..e7ee871b55b 100644 --- a/mysql-test/r/symlink.result +++ b/mysql-test/r/symlink.result @@ -22,7 +22,8 @@ insert into t1 (b) select b from t2; insert into t2 (b) select b from t1; insert into t1 (b) select b from t2; drop table t2; -create table t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="MYSQLTEST_VARDIR/tmp" index directory="MYSQLTEST_VARDIR/run"; +create table t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam data directory="MYSQLTEST_VARDIR/tmp" index directory="MYSQLTEST_VARDIR/run"; insert into t9 select * from t1; check table t9; Table Op Msg_type Msg_text @@ -56,11 +57,17 @@ t9 CREATE TABLE `t9` ( PRIMARY KEY (`a`) ) ENGINE=MyISAM AUTO_INCREMENT=16725 DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/' INDEX DIRECTORY='MYSQLTEST_VARDIR/run/' create database mysqltest; -create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="/this-dir-does-not-exist"; +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam index directory="/this-dir-does-not-exist"; Got one of the listed errors -create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="MYSQLTEST_VARDIR/run"; +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam index directory="not-hard-path"; +ERROR 42000: Incorrect table name 'not-hard-path' +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam index directory="MYSQLTEST_VARDIR/run"; Got one of the listed errors -create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="MYSQLTEST_VARDIR/tmp"; +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam data directory="MYSQLTEST_VARDIR/tmp"; Got one of the listed errors alter table t9 rename mysqltest.t9; select count(*) from mysqltest.t9; diff --git a/mysql-test/std_data/checkDBI_DBD-mysql.pl b/mysql-test/std_data/checkDBI_DBD-mysql.pl new file mode 100644 index 00000000000..f001e471081 --- /dev/null +++ b/mysql-test/std_data/checkDBI_DBD-mysql.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl + +# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# 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 +# Library 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +################################################################################ +# +# This perl script checks for availability of the Perl modules DBI and +# DBD::mysql using the "current" perl interpreter. +# +# Useful for test environment checking before testing executable perl scripts +# in the MySQL Server distribution. +# +# NOTE: The "shebang" on the first line of this script should always point to +# /usr/bin/perl, so that we can use this script to check whether or not we +# support running perl scripts with such a shebang without specifying the +# perl interpreter on the command line. Such a script is mysqlhotcopy. +# +# When run as "checkDBI_DBD-mysql.pl" the shebang line will be evaluated +# and used. When run as "perl checkDBI_DBD-mysql.pl" the shebang line is +# not used. +# +# NOTE: This script will create a temporary file in MTR's tmp dir. +# If modules are found, a mysql-test statement which sets a special +# variable is written to this file. If one of the modules is not found +# (or cannot be loaded), the file will remain empty. +# A test (or include file) which sources that file can then easily do +# an if-check on the special variable to determine success or failure. +# +# Example: +# +# --let $perlChecker= $MYSQLTEST_VARDIR/std_data/checkDBI_DBD-mysql.pl +# --let $resultFile= $MYSQL_TMP_DIR/dbidbd-mysql.txt +# --chmod 0755 $perlChecker +# --exec $perlChecker +# --source $resultFile +# if (!$dbidbd) { +# --skip Test needs Perl modules DBI and DBD::mysql +# } +# +# The calling script is also responsible for cleaning up after use: +# +# --remove_file $resultFile +# +# Windows notes: +# - shebangs may work differently - call this script with "perl " in front. +# +# See mysql-test/include/have_dbi_dbd-mysql.inc for example use of this script. +# This script should be executable for the user running MTR. +# +################################################################################ + +BEGIN { + # By using eval inside BEGIN we can suppress warnings and continue after. + # We need to catch "Can't locate" as well as "Can't load" errors. + eval{ + $FOUND_DBI=0; + $FOUND_DBD_MYSQL=0; + + # Check for DBI module: + $FOUND_DBI=1 if require DBI; + + # Check for DBD::mysql module + $FOUND_DBD_MYSQL=1 if require DBD::mysql; + }; +}; + +# Open a file to be used for transfer of result back to mysql-test. +# The file must be created whether we write to it or not, otherwise mysql-test +# will complain if trying to source it. +# An empty file indicates failure to load modules. +open(FILE, ">", $ENV{'MYSQL_TMP_DIR'}.'/dbidbd-mysql.txt'); + +if ($FOUND_DBI && $FOUND_DBD_MYSQL) { + # write a mysql-test command setting a variable to indicate success + print(FILE 'let $dbidbd= FOUND_DBI_DBD-MYSQL;'."\n"); +} + +# close the file. +close(FILE); + +1; + diff --git a/mysql-test/suite/engines/funcs/r/ps_string_not_null.result b/mysql-test/suite/engines/funcs/r/ps_string_not_null.result Binary files differindex 859fab8b490..5f2a630811c 100644 --- a/mysql-test/suite/engines/funcs/r/ps_string_not_null.result +++ b/mysql-test/suite/engines/funcs/r/ps_string_not_null.result diff --git a/mysql-test/suite/engines/funcs/t/ps_string_not_null.test b/mysql-test/suite/engines/funcs/t/ps_string_not_null.test index f9e937cb24d..662adfd7a88 100644 --- a/mysql-test/suite/engines/funcs/t/ps_string_not_null.test +++ b/mysql-test/suite/engines/funcs/t/ps_string_not_null.test @@ -1,5 +1,5 @@ --disable_warnings -DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t1; --enable_warnings CREATE TABLE t1(c1 CHAR(100) NOT NULL); PREPARE stmt1 FROM 'INSERT INTO t1 (c1) VALUES(?)'; diff --git a/mysql-test/suite/innodb/r/innodb_bug30423.result b/mysql-test/suite/innodb/r/innodb_bug30423.result new file mode 100644 index 00000000000..d7b72b1ec2a --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug30423.result @@ -0,0 +1,95 @@ +set global innodb_stats_method = default; +select @@innodb_stats_method; +@@innodb_stats_method +nulls_equal +select count(*) from bug30243_3 where org_id is not NULL; +count(*) +20 +select count(*) from bug30243_3 where org_id is NULL; +count(*) +16384 +select count(*) from bug30243_2 where org_id is not NULL; +count(*) +224 +select count(*) from bug30243_2 where org_id is NULL; +count(*) +65536 +select @@innodb_stats_method; +@@innodb_stats_method +nulls_equal +analyze table bug30243_1; +Table Op Msg_type Msg_text +test.bug30243_1 analyze status OK +analyze table bug30243_2; +Table Op Msg_type Msg_text +test.bug30243_2 analyze status OK +analyze table bug30243_3; +Table Op Msg_type Msg_text +test.bug30243_3 analyze status OK +set global innodb_stats_method = "NULL"; +ERROR 42000: Variable 'innodb_stats_method' can't be set to the value of 'NULL' +set global innodb_stats_method = "nulls_ignored"; +select @@innodb_stats_method; +@@innodb_stats_method +nulls_ignored +analyze table bug30243_1; +Table Op Msg_type Msg_text +test.bug30243_1 analyze status OK +analyze table bug30243_2; +Table Op Msg_type Msg_text +test.bug30243_2 analyze status OK +analyze table bug30243_3; +Table Op Msg_type Msg_text +test.bug30243_3 analyze status OK +explain SELECT COUNT(*), 0 +FROM bug30243_1 orgs +LEFT JOIN bug30243_3 sa_opportunities +ON orgs.org_id=sa_opportunities.org_id +LEFT JOIN bug30243_2 contacts +ON orgs.org_id=contacts.org_id ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE orgs index NULL org_id 4 NULL 128 Using index +1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id 1 Using index +1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id 1 Using index +select @@innodb_stats_method; +@@innodb_stats_method +nulls_ignored +set global innodb_stats_method = "nulls_unequal"; +select @@innodb_stats_method; +@@innodb_stats_method +nulls_unequal +analyze table bug30243_1; +Table Op Msg_type Msg_text +test.bug30243_1 analyze status OK +analyze table bug30243_2; +Table Op Msg_type Msg_text +test.bug30243_2 analyze status OK +analyze table bug30243_3; +Table Op Msg_type Msg_text +test.bug30243_3 analyze status OK +explain SELECT COUNT(*), 0 +FROM bug30243_1 orgs +LEFT JOIN bug30243_3 sa_opportunities +ON orgs.org_id=sa_opportunities.org_id +LEFT JOIN bug30243_2 contacts +ON orgs.org_id=contacts.org_id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE orgs index NULL org_id 4 NULL 128 Using index +1 SIMPLE sa_opportunities ref org_id org_id 5 test.orgs.org_id 1 Using index +1 SIMPLE contacts ref contacts$org_id contacts$org_id 5 test.orgs.org_id 1 Using index +SELECT COUNT(*) FROM table_bug30423 WHERE org_id IS NULL; +COUNT(*) +1024 +set global innodb_stats_method = "nulls_unequal"; +analyze table table_bug30423; +Table Op Msg_type Msg_text +test.table_bug30423 analyze status OK +set global innodb_stats_method = "nulls_ignored"; +analyze table table_bug30423; +Table Op Msg_type Msg_text +test.table_bug30423 analyze status OK +set global innodb_stats_method = nulls_equal; +drop table bug30243_2; +drop table bug30243_1; +drop table bug30243_3; +drop table table_bug30423; diff --git a/mysql-test/suite/innodb/r/innodb_gis.result b/mysql-test/suite/innodb/r/innodb_gis.result index 5712d08c9fa..9d015d91c0d 100644 --- a/mysql-test/suite/innodb/r/innodb_gis.result +++ b/mysql-test/suite/innodb/r/innodb_gis.result @@ -585,5 +585,17 @@ COUNT(*) 2 DROP TABLE t1, t2; End of 5.0 tests +# +# Test for bug #58650 "Failing assertion: primary_key_no == -1 || +# primary_key_no == 0". +# +drop table if exists t1; +# The minimal test case. +create table t1 (a int not null, b linestring not null, unique key b (b(12)), unique key a (a)); +drop table t1; +# The original test case. +create table t1 (a int not null, b linestring not null, unique key b (b(12))); +create unique index a on t1(a); +drop table t1; create table t1 (g geometry not null, spatial gk(g)) engine=innodb; ERROR HY000: The used table type doesn't support SPATIAL indexes diff --git a/mysql-test/suite/innodb/t/innodb_bug30423.test b/mysql-test/suite/innodb/t/innodb_bug30423.test new file mode 100644 index 00000000000..f2a3ee8d099 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug30423.test @@ -0,0 +1,211 @@ +# Test for Bug #30423, InnoDBs treatment of NULL in index stats causes +# bad "rows examined" estimates. +# Implemented InnoDB system variable "innodb_stats_method" with +# "nulls_equal" (default), "nulls_unequal", and "nulls_ignored" options. + +-- source include/have_innodb.inc + +let $innodb_stats_method_orig = `select @@innodb_stats_method`; + +# default setting for innodb_stats_method is "nulls_equal" +set global innodb_stats_method = default; + +select @@innodb_stats_method; + +# create three tables, bug30243_1, bug30243_2 and bug30243_3. +# The test scenario is adopted from original bug #30423 report. +# table bug30243_1 and bug30243_3 have many NULL values + +-- disable_result_log +-- disable_query_log + +DROP TABLE IF EXISTS bug30243_1; +CREATE TABLE bug30243_1 ( + org_id int(11) NOT NULL default '0', + UNIQUE KEY (org_id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +LOCK TABLES bug30243_1 WRITE; +INSERT INTO bug30243_1 VALUES (11),(15),(16),(17),(19),(20),(21),(23),(24), +(25),(26),(27),(28),(29),(30),(31),(32),(33),(34),(35),(37),(38),(40),(41), +(42),(43),(44),(45),(46),(47),(48),(49),(50),(51),(52),(53),(54),(55),(56), +(57),(58),(59),(60),(61),(62),(63),(64),(65),(66),(67),(68),(69),(70),(71), +(72),(73),(74),(75),(76),(77),(78),(79),(80),(81),(82),(83),(84),(85),(86), +(87),(88),(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101), +(102),(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114), +(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126),(127), +(128),(129),(130),(131),(132),(133),(134),(135),(136),(137),(138),(139),(140), +(141),(142),(143),(144),(145); +UNLOCK TABLES; + +DROP TABLE IF EXISTS bug30243_3; +CREATE TABLE bug30243_3 ( + org_id int(11) default NULL, + KEY (org_id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO bug30243_3 VALUES (NULL); + +begin; +let $i=14; +while ($i) +{ + INSERT INTO bug30243_3 SELECT NULL FROM bug30243_3; + dec $i; +} + +INSERT INTO bug30243_3 VALUES (34),(34),(35),(56),(58),(62),(62),(64),(65),(66),(80),(135),(137),(138),(139),(140),(142),(143),(144),(145); +commit; + +DROP TABLE IF EXISTS bug30243_2; +CREATE TABLE bug30243_2 ( + org_id int(11) default NULL, + KEY `contacts$org_id` (org_id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO bug30243_2 VALUES (NULL); + +begin; +let $i=16; +while ($i) +{ + INSERT INTO bug30243_2 SELECT NULL FROM bug30243_2; + dec $i; +} + +INSERT INTO bug30243_2 VALUES (11),(15),(16),(17),(20),(21),(23),(24),(25), +(26),(27),(28),(29),(30),(31),(32),(33),(34),(37),(38),(40),(41),(42),(43), +(44),(45),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46), +(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46), +(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46), +(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46), +(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46), +(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(46),(48), +(48),(50),(51),(52),(52),(53),(54),(55),(57),(60),(61),(62),(62),(62),(62), +(62),(63),(64),(64),(65),(66),(66),(67),(68),(69),(70),(71),(72),(73),(74), +(75),(76),(77),(78),(79),(80),(80),(81),(82),(83),(84),(85),(86),(87),(88), +(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101),(102), +(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114), +(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126), +(127),(128),(129),(130),(131),(132),(133),(133),(135),(135),(135),(135), +(136),(136),(138),(138),(139),(139),(139),(140),(141),(141),(142),(143), +(143),(145),(145); +commit; + + +-- enable_result_log +-- enable_query_log + +# check tables's value +select count(*) from bug30243_3 where org_id is not NULL; +select count(*) from bug30243_3 where org_id is NULL; + +select count(*) from bug30243_2 where org_id is not NULL; +select count(*) from bug30243_2 where org_id is NULL; + +select @@innodb_stats_method; + +analyze table bug30243_1; +analyze table bug30243_2; +analyze table bug30243_3; + +# Following query plan shows that we over estimate the rows per +# unique value (since there are many NULLs). +# Skip this query log since the stats estimate could vary from runs +-- disable_query_log +-- disable_result_log +explain SELECT COUNT(*), 0 + FROM bug30243_1 orgs + LEFT JOIN bug30243_3 sa_opportunities + ON orgs.org_id=sa_opportunities.org_id + LEFT JOIN bug30243_2 contacts + ON orgs.org_id=contacts.org_id ; +-- enable_query_log +-- enable_result_log + +# following set operation will fail +#--error ER_WRONG_VALUE_FOR_VAR +--error 1231 +set global innodb_stats_method = "NULL"; + +set global innodb_stats_method = "nulls_ignored"; + +select @@innodb_stats_method; + +# Regenerate the stats with "nulls_ignored" option + +analyze table bug30243_1; +analyze table bug30243_2; +analyze table bug30243_3; + +# Following query plan shows that we get the correct rows per +# unique value (should be approximately 1 row per value) +explain SELECT COUNT(*), 0 + FROM bug30243_1 orgs + LEFT JOIN bug30243_3 sa_opportunities + ON orgs.org_id=sa_opportunities.org_id + LEFT JOIN bug30243_2 contacts + ON orgs.org_id=contacts.org_id ; + +select @@innodb_stats_method; + +# Try the "nulls_unequal" option +set global innodb_stats_method = "nulls_unequal"; + +select @@innodb_stats_method; + +analyze table bug30243_1; +analyze table bug30243_2; +analyze table bug30243_3; + +# Following query plan shows that we get the correct rows per +# unique value (~1) +explain SELECT COUNT(*), 0 + FROM bug30243_1 orgs + LEFT JOIN bug30243_3 sa_opportunities + ON orgs.org_id=sa_opportunities.org_id + LEFT JOIN bug30243_2 contacts + ON orgs.org_id=contacts.org_id; + + +# Create a table with all NULL values, make sure the stats calculation +# does not crash with table of all NULL values +-- disable_query_log +CREATE TABLE table_bug30423 ( + org_id int(11) default NULL, + KEY(org_id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `table_bug30423` VALUES (NULL); + +begin; +let $i=10; +while ($i) +{ + INSERT INTO table_bug30423 SELECT NULL FROM table_bug30423; + dec $i; +} +commit; + +-- enable_query_log + +SELECT COUNT(*) FROM table_bug30423 WHERE org_id IS NULL; + +# calculate the statistics for the table for "nulls_ignored" and +# "nulls_unequal" option +set global innodb_stats_method = "nulls_unequal"; +analyze table table_bug30423; + +set global innodb_stats_method = "nulls_ignored"; +analyze table table_bug30423; + + +eval set global innodb_stats_method = $innodb_stats_method_orig; + +drop table bug30243_2; + +drop table bug30243_1; + +drop table bug30243_3; + +drop table table_bug30423; diff --git a/mysql-test/suite/innodb/t/innodb_bug56143.test b/mysql-test/suite/innodb/t/innodb_bug56143.test index 3b46f7e1621..c21de09892c 100644 --- a/mysql-test/suite/innodb/t/innodb_bug56143.test +++ b/mysql-test/suite/innodb/t/innodb_bug56143.test @@ -8,6 +8,11 @@ -- disable_query_log -- disable_result_log +if ($VALGRIND_TEST) +{ + call mtr.add_suppression("InnoDB: Warning: a long semaphore wait:"); +} + SET foreign_key_checks=0; DROP TABLE IF EXISTS bug56143_1; diff --git a/mysql-test/suite/parts/inc/partition_layout_check1.inc b/mysql-test/suite/parts/inc/partition_layout_check1.inc index 1b0b24f1088..de35d3f2cad 100644 --- a/mysql-test/suite/parts/inc/partition_layout_check1.inc +++ b/mysql-test/suite/parts/inc/partition_layout_check1.inc @@ -29,14 +29,10 @@ DELETE FROM t0_definition; let $MYSQLD_DATADIR= `select LEFT(@@datadir, LENGTH(@@datadir)-1)`; #echo MYSQLD_DATADIR: $MYSQLD_DATADIR; -# Dump the current definition of the table t1 to tmp1 -# This complicated method - let another mysqltest collect the output - is used -# because of two reasons +# Save the current definition of the table t1 # - SHOW CREATE TABLE t1 is at least currently most probably more reliable than # the corresponding SELECT on the INFORMATION_SCHEMA -# - SHOW CREATE TABLE .. cannot write its out put into a file like SELECT -let $show_file= $MYSQLD_DATADIR/test/tmp1; ---exec echo "SHOW CREATE TABLE t1; exit; " | $MYSQL_TEST > $show_file 2>&1 +let $show_create= `SHOW CREATE TABLE t1`; if ($do_file_tests) { # List the files belonging to the table t1 @@ -57,12 +53,13 @@ if (!$do_file_tests) # Insert the current definition of the table t1 into t0_definition eval INSERT INTO t0_definition SET state = 'old', - create_command = load_file('$show_file'), + create_command = "$show_create", file_list = @aux; # Print the create table statement into the protocol +# Added the concat to avoid changing the result files --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR '\r' '' -SELECT create_command FROM t0_definition WHERE state = 'old'; +SELECT concat('SHOW CREATE TABLE t1;\nTable\tCreate Table\n',create_command,'\n') as `create_command` FROM t0_definition WHERE state = 'old'; if ($do_file_tests) { # We stored the list of files, therefore printing the content makes sense diff --git a/mysql-test/suite/parts/inc/partition_layout_check2.inc b/mysql-test/suite/parts/inc/partition_layout_check2.inc index b1ec56ceedd..028b1242e90 100644 --- a/mysql-test/suite/parts/inc/partition_layout_check2.inc +++ b/mysql-test/suite/parts/inc/partition_layout_check2.inc @@ -28,9 +28,8 @@ DELETE FROM t0_definition WHERE state = 'new'; let $MYSQLD_DATADIR= `select LEFT(@@datadir, LENGTH(@@datadir)-1)`; #echo MYSQLD_DATADIR: $MYSQLD_DATADIR; -# Dump the current definition of the table t1 to tmp1 -let $show_file= $MYSQLD_DATADIR/test/tmp1; ---exec echo "SHOW CREATE TABLE t1; exit; " | $MYSQL_TEST > $show_file 2>&1 +# Save the current definition of the table t1 +let $show_create= `SHOW CREATE TABLE t1`; if ($do_file_tests) { @@ -52,7 +51,7 @@ if (!$do_file_tests) # Insert the current definition of the table t1 into t0_definition eval INSERT INTO t0_definition SET state = 'new', - create_command = load_file('$show_file'), + create_command = "$show_create", file_list = @aux; # Print the old and new table layout, if they differ diff --git a/mysql-test/suite/parts/t/partition_recover_myisam.test b/mysql-test/suite/parts/t/partition_recover_myisam.test index ecc83629768..79a85ca222f 100644 --- a/mysql-test/suite/parts/t/partition_recover_myisam.test +++ b/mysql-test/suite/parts/t/partition_recover_myisam.test @@ -20,6 +20,8 @@ FLUSH TABLES; let $MYSQLD_DATADIR= `select @@datadir`; --remove_file $MYSQLD_DATADIR/test/t1_will_crash.MYI --copy_file std_data/corrupt_t1.MYI $MYSQLD_DATADIR/test/t1_will_crash.MYI +--replace_result \\ / +--replace_regex /Table '.*data/Table './ SELECT * FROM t1_will_crash; DROP TABLE t1_will_crash; CREATE TABLE t1_will_crash (a INT, KEY (a)) @@ -33,5 +35,7 @@ FLUSH TABLES; --echo # head -c1024 t1#P#p1.MYI > corrupt_t1#P#p1.MYI --remove_file $MYSQLD_DATADIR/test/t1_will_crash#P#p1.MYI --copy_file std_data/corrupt_t1#P#p1.MYI $MYSQLD_DATADIR/test/t1_will_crash#P#p1.MYI +--replace_result \\ / +--replace_regex /Table '.*data/Table './ SELECT * FROM t1_will_crash; DROP TABLE t1_will_crash; diff --git a/mysql-test/suite/parts/t/partition_special_innodb.test b/mysql-test/suite/parts/t/partition_special_innodb.test index 1c36299f4bd..1fc9ac7fafc 100644 --- a/mysql-test/suite/parts/t/partition_special_innodb.test +++ b/mysql-test/suite/parts/t/partition_special_innodb.test @@ -58,8 +58,8 @@ ENGINE = InnoDB PARTITION BY HASH (a) PARTITIONS 2; -connect (con1,127.0.0.1,root,,test,$MASTER_MYPORT,); -connect (con2,127.0.0.1,root,,test,$MASTER_MYPORT,); +connect (con1, localhost, root,,); +connect (con2, localhost, root,,); --connection con1 SET autocommit=OFF; diff --git a/mysql-test/suite/rpl/r/rpl_circular_for_4_hosts.result b/mysql-test/suite/rpl/r/rpl_circular_for_4_hosts.result index fb1d3f8258e..6981e549918 100644 --- a/mysql-test/suite/rpl/r/rpl_circular_for_4_hosts.result +++ b/mysql-test/suite/rpl/r/rpl_circular_for_4_hosts.result @@ -121,11 +121,11 @@ Master D 12 D * Remove wrong event from C and restore B->C->D * include/stop_slave.inc DELETE FROM t1 WHERE a = 6; -START SLAVE; +include/start_slave.inc RESET MASTER; RESET SLAVE; include/rpl_change_topology.inc [new topology=1->2->3->4->1] -START SLAVE; +include/start_slave.inc include/rpl_sync.inc * Check data inserted before restoring schema A->B->C->D->A * diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result b/mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result index 198d89ae3d6..e0e6df064b9 100644 --- a/mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result +++ b/mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result @@ -2,13 +2,21 @@ include/rpl_init.inc [topology=1->2,1->3] include/rpl_connect.inc [creating master] include/rpl_connect.inc [creating slave_1] include/rpl_connect.inc [creating slave_2] +include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD = 0.1; +include/start_slave.inc +include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD = 1; +include/start_slave.inc Slave has received heartbeat event -slave_2 has received heartbeat event -slave_1 has received more heartbeats than slave_2 (1 means 'yes'): 0 +include/assert.inc [slave_1 should have received more heartbeats than slave_2] include/rpl_stop_slaves.inc include/rpl_change_topology.inc [new topology=1->3->2] include/rpl_start_slaves.inc +include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0.1; +include/start_slave.inc slave_1 has received heartbeat event [on master] CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10), c LONGTEXT); @@ -26,7 +34,7 @@ Tables_in_test [on master] creating updates on master and send to slave_2 during 5 second [on slave_1] -slave_1 has received heartbeats (1 means 'yes'): 0 +include/assert.inc [slave_1 should have received heartbeats] *** Clean up *** DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_insert_duplicate.result b/mysql-test/suite/rpl/r/rpl_insert_duplicate.result new file mode 100644 index 00000000000..61ebbaaa5a9 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_insert_duplicate.result @@ -0,0 +1,29 @@ +include/master-slave.inc +[connection master] +CREATE TABLE t1 ( +a INT UNSIGNED NOT NULL PRIMARY KEY +) ENGINE=innodb; +CREATE TABLE t2 ( +a INT UNSIGNED +) ENGINE=innodb; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a; +include/assert.inc [Sum of elements in t1 should be 1.] +include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] +include/diff_tables.inc [master:test.t1 , slave:test.t1] +drop table t1, t2; +CREATE TABLE t1 ( +a INT UNSIGNED NOT NULL PRIMARY KEY +) ENGINE=myisam; +CREATE TABLE t2 ( +a INT UNSIGNED +) ENGINE=myisam; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a; +include/assert.inc [Sum of elements in t1 should be 1.] +include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] +include/diff_tables.inc [master:test.t1 , slave:test.t1] +drop table t1, t2; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_insert_ignore.result b/mysql-test/suite/rpl/r/rpl_insert_ignore.result index e31272f5300..04b64359126 100644 --- a/mysql-test/suite/rpl/r/rpl_insert_ignore.result +++ b/mysql-test/suite/rpl/r/rpl_insert_ignore.result @@ -21,48 +21,36 @@ INSERT INTO t2 VALUES (4, 3); INSERT INTO t2 VALUES (5, 4); INSERT INTO t2 VALUES (6, 6); INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; -SELECT * FROM t1 ORDER BY a; -a b -1 1 -2 2 -3 3 -4 4 -5 5 -6 6 -SELECT * FROM t1 ORDER BY a; -a b -1 1 -2 2 -3 3 -4 4 -5 5 -6 6 -drop table t1; +include/assert.inc [Count of elements in t1 should be 6.] +include/diff_tables.inc [master:test.t1 , slave:test.t1] +INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; +include/assert.inc [Count of elements in t1 should be 6.] +include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] +drop table t1, t2; CREATE TABLE t1 ( a int unsigned not null auto_increment primary key, b int unsigned, unique (b) ) ENGINE=myisam; -INSERT INTO t1 VALUES (1, 1); -INSERT INTO t1 VALUES (2, 2); -INSERT INTO t1 VALUES (3, 3); -INSERT INTO t1 VALUES (4, 4); +CREATE TABLE t2 ( +a int unsigned, # to force INSERT SELECT to have a certain order +b int unsigned +) ENGINE=myisam; +INSERT INTO t1 VALUES (NULL, 1); +INSERT INTO t1 VALUES (NULL, 2); +INSERT INTO t1 VALUES (NULL, 3); +INSERT INTO t1 VALUES (NULL, 4); +INSERT INTO t2 VALUES (1, 1); +INSERT INTO t2 VALUES (2, 2); +INSERT INTO t2 VALUES (3, 5); +INSERT INTO t2 VALUES (4, 3); +INSERT INTO t2 VALUES (5, 4); +INSERT INTO t2 VALUES (6, 6); +INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; +include/assert.inc [Count of elements in t1 should be 6.] +include/diff_tables.inc [master:test.t1 , slave:test.t1] INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; -SELECT * FROM t1 ORDER BY a; -a b -1 1 -2 2 -3 3 -4 4 -5 5 -6 6 -SELECT * FROM t1 ORDER BY a; -a b -1 1 -2 2 -3 3 -4 4 -5 5 -6 6 +include/assert.inc [Count of elements in t1 should be 6.] +include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] drop table t1, t2; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index b2224dcd725..91d307008f0 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -9,7 +9,7 @@ change master to master_log_pos=MASTER_LOG_POS; Read_Master_Log_Pos = '75' start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'' include/stop_slave_sql.inc show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 9f49dfd7714..1aa596ec783 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -14,7 +14,6 @@ rpl_failed_optimize : WL#4284: Can't optimize table used by a pending tran rpl_read_only : WL#4284: Setting Read only won't succeed until all metadata locks are released. rpl_row_create_table : Bug#51574 2010-02-27 andrei failed different way than earlier with bug#45576 rpl_spec_variables : BUG#47661 2009-10-27 jasonh rpl_spec_variables fails on PB2 hpux -rpl_log_pos : BUG#55675 2010-09-10 alfranio rpl.rpl_log_pos fails sporadically with error binlog truncated in the middle rpl_get_master_version_and_clock : Bug#59178 Jan 05 2011 joro Valgrind warnings rpl_get_master_version_and_clock rpl_row_until : BUG#59543 Jan 26 2011 alfranio Replication test from eits suite rpl_row_until times out rpl_stm_until : BUG#59543 Jan 26 2011 alfranio Replication test from eits suite rpl_row_until times out diff --git a/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.test b/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.test index 888f09fcfa1..750f399ce99 100644 --- a/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.test +++ b/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.test @@ -178,7 +178,7 @@ SELECT 'Master D',a,b FROM t1 WHERE c = 3 ORDER BY a,b; source include/stop_slave.inc; --connection server_3 DELETE FROM t1 WHERE a = 6; -START SLAVE; +--source include/start_slave.inc --connection server_2 --sync_slave_with_master server_3 RESET MASTER; @@ -192,7 +192,7 @@ RESET SLAVE; --source include/rpl_change_topology.inc #--replace_result $SERVER_MYPORT_3 SERVER_MYPORT_3 $file_d LOG_FILE $pos_d LOG_POS #--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$SERVER_MYPORT_3,master_user='root',master_log_file='$file_d',master_log_pos=$pos_d -START SLAVE; +--source include/start_slave.inc --connection server_3 --sync_slave_with_master server_4 --source include/rpl_sync.inc diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test index a7b44215779..6bdd2bbee63 100644 --- a/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test @@ -20,7 +20,19 @@ --source include/rpl_connect.inc # -# Testing heartbeat +# Set different heartbeat periods for slaves +# +--connection slave_1 +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD = 0.1; +--source include/start_slave.inc +--connection slave_2 +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD = 1; +--source include/start_slave.inc + +# +# Testing heartbeat for one master and two slaves # # Check that heartbeat events sent to both slaves with correct periods @@ -35,15 +47,11 @@ let $status_var= slave_received_heartbeats; let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); let $status_var_comparsion= >; --source include/wait_for_status_var.inc -let $slave_2_rcvd_heartbeats= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); ---echo slave_2 has received heartbeat event ---connection slave_1 -let $slave_1_rcvd_heartbeats= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); -let $result= query_get_value(SELECT ($slave_1_rcvd_heartbeats DIV $slave_2_rcvd_heartbeats) > 1 AS Result, Result, 1); ---echo slave_1 has received more heartbeats than slave_2 (1 means 'yes'): $result +--let $assert_cond= [slave_1:SHOW STATUS LIKE "slave_received_heartbeats", Value, 1] > [slave_2:SHOW STATUS LIKE "slave_received_heartbeats", Value, 1] +--let $assert_text= slave_1 should have received more heartbeats than slave_2 +--source include/assert.inc --echo - # Create topology master->slave_2->slave_1 and check that slave_1 # receives heartbeat while slave_2 gets data. @@ -54,6 +62,10 @@ let $result= query_get_value(SELECT ($slave_1_rcvd_heartbeats DIV $slave_2_rcvd_ --let $rpl_topology= 1->3->2 --source include/rpl_change_topology.inc --source include/rpl_start_slaves.inc +--connection slave_1 +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc # Check heartbeat for new replication channel slave_2->slave let $status_var= slave_received_heartbeats; @@ -93,8 +105,6 @@ while ($i) { let $time_before = `SELECT NOW()`; } if (`SELECT ((1-$k)*TIMESTAMPDIFF(SECOND,'$time_before',NOW())) > 5`) { - --connection slave_1 - let $slave_1_rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); let $i= 0; } --connection master @@ -104,8 +114,9 @@ while ($i) { --enable_query_log --connection slave_1 --echo [on slave_1] -let $result= query_get_value(SELECT ($slave_1_rcvd_heartbeats_after - $slave_1_rcvd_heartbeats_before) > 0 AS Result, Result, 1); ---echo slave_1 has received heartbeats (1 means 'yes'): $result +--let $assert_cond= [SHOW STATUS LIKE "slave_received_heartbeats", Value, 1] > $slave_1_rcvd_heartbeats_before +--let $assert_text= slave_1 should have received heartbeats +--source include/assert.inc --echo # diff --git a/mysql-test/suite/rpl/t/rpl_insert_duplicate.test b/mysql-test/suite/rpl/t/rpl_insert_duplicate.test new file mode 100644 index 00000000000..7dd38a696ae --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_insert_duplicate.test @@ -0,0 +1,14 @@ +######################################### +# Wrapper for rpl_insert_duplicate.test # +######################################### +-- source include/master-slave.inc +-- source include/have_innodb.inc +#-- source include/have_binlog_format_mixed_or_statement.inc + +let $engine_type=innodb; +-- source extra/rpl_tests/rpl_insert_duplicate.test + +let $engine_type=myisam; +-- source extra/rpl_tests/rpl_insert_duplicate.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_insert_ignore.test b/mysql-test/suite/rpl/t/rpl_insert_ignore.test index f8887c96b55..0346975fcee 100644 --- a/mysql-test/suite/rpl/t/rpl_insert_ignore.test +++ b/mysql-test/suite/rpl/t/rpl_insert_ignore.test @@ -7,7 +7,10 @@ call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); -let $engine_type=innodb; -let $engine_type2=myisam; +-- let $engine_type=innodb -- source extra/rpl_tests/rpl_insert_ignore.test + +-- let $engine_type=myisam +-- source extra/rpl_tests/rpl_insert_ignore.test + --source include/rpl_end.inc diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index e635f1201a3..418330f078d 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -11,7 +11,9 @@ There should be *no* long test name listed below: select variable_name as `There should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; There should be *no* variables listed below: +INNODB_STATS_METHOD INNODB_FILE_FORMAT_MAX +INNODB_STATS_METHOD INNODB_FILE_FORMAT_MAX drop table t1; drop table t2; diff --git a/mysql-test/t/csv_not_null.test b/mysql-test/t/csv_not_null.test index 03ed566fb22..bebea53b2f7 100644 --- a/mysql-test/t/csv_not_null.test +++ b/mysql-test/t/csv_not_null.test @@ -55,10 +55,8 @@ INSERT INTO t1 VALUES(); SELECT * FROM t1; -- disable_warnings -# NOTE - Test disabled due to enum crash for this INSERT -# See Bug#33717 - INSERT...(default) fails for enum. -# Crashes CSV tables, loads spaces for MyISAM -#INSERT INTO t1 VALUES(default,default,default,default,default,default); +# Bug#33717 - INSERT...(default) fails for enum. +INSERT INTO t1 VALUES(default,default,default,default,default,default); -- enable_warnings SELECT * FROM t1; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 60af4159650..985493481e9 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,8 +11,6 @@ ############################################################################## lowercase_table3 : Bug#54845 2010-06-30 alik main.lowercase_table3 on Mac OSX query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically -main.mysqlhotcopy_myisam : Bug#56817 2010-10-21 anitha mysqlhotcopy* fails -main.mysqlhotcopy_archive: Bug#56817 2010-10-21 anitha mysqlhotcopy* fails log_tables-big : Bug#48646 2010-11-15 mattiasj report already exists read_many_rows_innodb : Bug#37635 2010-11-15 mattiasj report already exists sum_distinct-big : Bug#56927 2010-11-15 mattiasj was not tested diff --git a/mysql-test/t/filesort_debug.test b/mysql-test/t/filesort_debug.test new file mode 100644 index 00000000000..0058a6a3aa7 --- /dev/null +++ b/mysql-test/t/filesort_debug.test @@ -0,0 +1,23 @@ +--source include/have_debug.inc + +SET @old_debug= @@session.debug; + +--echo # +--echo # Bug#36022 please log more information about "Sort aborted" queries +--echo # + +CREATE TABLE t1(f0 int auto_increment primary key, f1 int); +INSERT INTO t1(f1) VALUES (0),(1),(2),(3),(4),(5); + +SET session debug= '+d,make_char_array_fail'; +CALL mtr.add_suppression("Out of sort memory"); +--error ER_OUT_OF_SORTMEMORY +SELECT * FROM t1 ORDER BY f1 ASC, f0; +SET session debug= @old_debug; + +CREATE FUNCTION f1() RETURNS INT RETURN 1; +--error ER_SP_WRONG_NO_OF_ARGS +DELETE FROM t1 ORDER BY (f1(10)) LIMIT 1; + +DROP TABLE t1; +DROP FUNCTION f1; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 2c4a7f4c7b1..a0527f70b25 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1120,6 +1120,17 @@ SELECT RELEASE_LOCK('aaaaaaaaaaaaaaaaa'); --echo # --echo End of 5.1 tests +### +--echo # +--echo # Bug#52123 Assertion failed: aggregator == aggr->Aggrtype(), +--echo # file .\item_sum.cc, line 587 +--echo # + +CREATE TABLE t1(a int, KEY(a)); +INSERT INTO t1 VALUES (1), (2); +SELECT 1 FROM t1 ORDER BY AVG(DISTINCT a); +DROP TABLE t1; + --echo # --echo # Bug#55648: Server crash on MIN/MAX on maximum time value --echo # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 25600a2d583..eaa592c2ad5 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -802,6 +802,26 @@ select LAST_DAY('2007-12-06 08:59:19.05') - INTERVAL 1 SECOND; select date_add('1000-01-01 00:00:00', interval '1.03:02:01.05' day_microsecond); select date_add('1000-01-01 00:00:00', interval '1.02' day_microsecond); + +--echo # +--echo # Bug #52315 part 2 : utc_date() crashes when system time > year 2037 +--echo # + +--disable_result_log +SET TIMESTAMP=-147490000; SELECT UTC_TIMESTAMP(); +--error ER_WRONG_VALUE_FOR_VAR +SET TIMESTAMP=2147483648; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483646; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483647; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=0; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=-1; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=1; SELECT UTC_TIMESTAMP(); +--enable_result_log + +#reset back the timestamp value +SET TIMESTAMP=0; + + --echo End of 5.0 tests # diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 72d27d3571a..991854cfb78 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -1092,4 +1092,128 @@ FROM BB table1 RIGHT JOIN BB table2 DROP TABLE BB; + +--echo # +--echo # Bug#58490: Incorrect result in multi level OUTER JOIN +--echo # in combination with IS NULL +--echo # + +CREATE TABLE t1 (i INT NOT NULL); +INSERT INTO t1 VALUES (0), (2),(3),(4); +CREATE TABLE t2 (i INT NOT NULL); +INSERT INTO t2 VALUES (0),(1), (3),(4); +CREATE TABLE t3 (i INT NOT NULL); +INSERT INTO t3 VALUES (0),(1),(2), (4); +CREATE TABLE t4 (i INT NOT NULL); +INSERT INTO t4 VALUES (0),(1),(2),(3) ; + +SELECT * FROM + t1 LEFT JOIN + ( t2 LEFT JOIN + ( t3 LEFT JOIN + t4 + ON t4.i = t3.i + ) + ON t3.i = t2.i + ) + ON t2.i = t1.i + ; + +SELECT * FROM + t1 LEFT JOIN + ( t2 LEFT JOIN + ( t3 LEFT JOIN + t4 + ON t4.i = t3.i + ) + ON t3.i = t2.i + ) + ON t2.i = t1.i + WHERE t4.i IS NULL; + + +# Most simplified testcase to reproduce the bug. +# (Has to be at least a two level nested outer join) +SELECT * FROM + t1 LEFT JOIN + ( ( t2 LEFT JOIN + t3 + ON t3.i = t2.i + ) + ) + ON t2.i = t1.i + WHERE t3.i IS NULL; + + +# Extended testing: +# We then add some equi-join inside the query above: +# (There Used to be some problems here with first +# proposed patch for this bug) +SELECT * FROM + t1 LEFT JOIN + ( ( t2 LEFT JOIN + t3 + ON t3.i = t2.i + ) + JOIN t4 + ON t4.i=t2.i + ) + ON t2.i = t1.i + WHERE t3.i IS NULL; + +SELECT * FROM + t1 LEFT JOIN + ( ( t2 LEFT JOIN + t3 + ON t3.i = t2.i + ) + JOIN (t4 AS t4a JOIN t4 AS t4b ON t4a.i=t4b.i) + ON t4a.i=t2.i + ) + ON t2.i = t1.i + WHERE t3.i IS NULL; + +SELECT * FROM + t1 LEFT JOIN + ( ( t2 LEFT JOIN + t3 + ON t3.i = t2.i + ) + JOIN (t4 AS t4a, t4 AS t4b) + ON t4a.i=t2.i + ) + ON t2.i = t1.i + WHERE t3.i IS NULL; + + +DROP TABLE t1,t2,t3,t4; + +## Bug#49322 & bug#58490 are duplicates. However, we include testcases +## for both. +--echo # +--echo # Bug#49322(Duplicate): Server is adding extra NULL row +--echo # on processing a WHERE clause +--echo # + +CREATE TABLE h (pk INT NOT NULL, col_int_key INT); +INSERT INTO h VALUES (1,NULL),(4,2),(5,2),(3,4),(2,8); + +CREATE TABLE m (pk INT NOT NULL, col_int_key INT); +INSERT INTO m VALUES (1,2),(2,7),(3,5),(4,7),(5,5),(6,NULL),(7,NULL),(8,9); +CREATE TABLE k (pk INT NOT NULL, col_int_key INT); +INSERT INTO k VALUES (1,9),(2,2),(3,5),(4,2),(5,7),(6,0),(7,5); + +# Baseline query wo/ 'WHERE ... IS NULL' - was correct +SELECT TABLE1.pk FROM k TABLE1 +RIGHT JOIN h TABLE2 ON TABLE1.col_int_key=TABLE2.col_int_key +RIGHT JOIN m TABLE4 ON TABLE2.col_int_key=TABLE4.col_int_key; + +# Adding 'WHERE ... IS NULL' -> incorrect result +SELECT TABLE1.pk FROM k TABLE1 +RIGHT JOIN h TABLE2 ON TABLE1.col_int_key=TABLE2.col_int_key +RIGHT JOIN m TABLE4 ON TABLE2.col_int_key=TABLE4.col_int_key +WHERE TABLE1.pk IS NULL; + +DROP TABLE h,m,k; + --echo End of 5.1 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 7b5b2a0ded0..a7c9dc54042 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -425,6 +425,12 @@ drop table t1; --echo --exec $MYSQL --skip-column-names --vertical test -e "select 1 as a" +# +# Bug#57450: mysql client enter in an infinite loop if the standard input is a directory +# +--error 1 +--exec $MYSQL < . + --echo --echo # diff --git a/mysql-test/t/not_embedded_server.test b/mysql-test/t/not_embedded_server.test index c1dbba82292..5b99c37ee29 100644 --- a/mysql-test/t/not_embedded_server.test +++ b/mysql-test/t/not_embedded_server.test @@ -14,6 +14,16 @@ call mtr.add_suppression("Can't open and lock privilege tables: Table 'host' was SHOW VARIABLES like 'slave_skip_errors'; +--echo # +--echo # Bug#58026: massive recursion and crash in regular expression handling +--echo # + +--disable_result_log +--error ER_STACK_OVERRUN_NEED_MORE +SELECT '1' RLIKE RPAD('1', 10000, '('); +--enable_result_log + + # End of 5.1 tests --echo # diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 7869a01a84d..5998d6269fb 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -843,7 +843,8 @@ create table t1(a int, b tinytext); insert into t1 values (1,2),(3,2); set session sort_buffer_size= 30000; set session max_sort_length= 2180; ---error 1038 +CALL mtr.add_suppression("Out of sort memory"); +--error ER_OUT_OF_SORTMEMORY select * from t1 order by b; drop table t1; @@ -1492,6 +1493,23 @@ LIMIT 2; DROP TABLE t1, t2; +--echo # +--echo # Bug #59110: Memory leak of QUICK_SELECT_I allocated memory +--echo # and +--echo # Bug #59308: Incorrect result for +--echo SELECT DISTINCT <col>... ORDER BY <col> DESC +--echo +--echo # Use Valgrind to detect #59110! +--echo # + +CREATE TABLE t1 (a INT,KEY (a)); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); + +EXPLAIN SELECT DISTINCT a,1 FROM t1 WHERE a <> 1 ORDER BY a DESC; +SELECT DISTINCT a,1 FROM t1 WHERE a <> 1 ORDER BY a DESC; + +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/plugin_auth.test b/mysql-test/t/plugin_auth.test index 5efb50a41e1..753593efc94 100644 --- a/mysql-test/t/plugin_auth.test +++ b/mysql-test/t/plugin_auth.test @@ -411,4 +411,26 @@ FLUSH PRIVILEGES; --echo # Executing 'mysql_upgrade' --exec $MYSQL_UPGRADE -u root -S $MASTER_MYSOCK -P $MASTER_MYPORT --default-auth=auth_test_plugin $PLUGIN_AUTH_OPT --skip-verbose --force --upgrade-system-tables +--echo # +--echo # Bug #59657: Move the client authentication_pam plugin into the +--echo # server repository +--echo # + +CREATE USER uplain@localhost IDENTIFIED WITH 'cleartext_plugin_server' + AS 'cleartext_test'; + +--echo ## test plugin auth +--disable_query_log +--error ER_ACCESS_DENIED_ERROR : this should fail : no grant +connect(cleartext_fail_con,localhost,uplain,cleartext_test2); +--enable_query_log + +connect(cleartext_con,localhost,uplain,cleartext_test); +connection cleartext_con; +select USER(),CURRENT_USER(); + +connection default; +disconnect cleartext_con; +DROP USER uplain@localhost; + --echo End of 5.5 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 0ad3d3e8504..6c9320b708a 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1325,4 +1325,71 @@ SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key; DROP TABLE t1; +--echo # +--echo # Bug #57030: 'BETWEEN' evaluation is incorrect +--echo # + +# Test some BETWEEN predicates which does *not* follow the +# 'normal' pattern of <field> BETWEEN <low const> AND <high const> + +CREATE TABLE t1(pk INT PRIMARY KEY, i4 INT); +CREATE UNIQUE INDEX i4_uq ON t1(i4); + +INSERT INTO t1 VALUES (1,10), (2,20), (3,30); + +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10; +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 10; + +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4; +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND i4; + +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4; +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND i4; + +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10; +SELECT * FROM t1 WHERE 10 BETWEEN i4 AND 10; + +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10; +SELECT * FROM t1 WHERE 10 BETWEEN 10 AND 10; + +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11; +SELECT * FROM t1 WHERE 10 BETWEEN 11 AND 11; + +EXPLAIN +SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0; +SELECT * FROM t1 WHERE 10 BETWEEN 100 AND 0; + +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0; +SELECT * FROM t1 WHERE i4 BETWEEN 100 AND 0; + +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999; +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND 99999999999999999; + +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30; +SELECT * FROM t1 WHERE i4 BETWEEN 999999999999999 AND 30; + +EXPLAIN +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20'; +SELECT * FROM t1 WHERE i4 BETWEEN 10 AND '20'; + +#Should detect the EQ_REF 't2.pk=t1.i4' +EXPLAIN +SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4; +SELECT * FROM t1, t1 as t2 WHERE t2.pk BETWEEN t1.i4 AND t1.i4; + +EXPLAIN +SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk; +SELECT * FROM t1, t1 as t2 WHERE t1.i4 BETWEEN t2.pk AND t2.pk; + +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/ssl_and_innodb.test b/mysql-test/t/ssl_and_innodb.test new file mode 100644 index 00000000000..4966f05b37b --- /dev/null +++ b/mysql-test/t/ssl_and_innodb.test @@ -0,0 +1,11 @@ +-- source include/have_innodb.inc +-- source include/have_ssl_crypto_functs.inc + +CREATE TABLE t1(a int) engine=innodb; +INSERT INTO t1 VALUES (1); + +SELECT DISTINCT +convert((SELECT des_decrypt(2,1) AS a FROM t1 WHERE @a:=1), signed) as d +FROM t1 ; + +DROP TABLE t1; diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test index 073fcd28246..87b874bc81f 100644 --- a/mysql-test/t/symlink.test +++ b/mysql-test/t/symlink.test @@ -39,7 +39,8 @@ drop table t2; # --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval create table t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="$MYSQLTEST_VARDIR/tmp" index directory="$MYSQLTEST_VARDIR/run"; +eval create table t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam data directory="$MYSQLTEST_VARDIR/tmp" index directory="$MYSQLTEST_VARDIR/run"; insert into t9 select * from t1; check table t9; @@ -71,21 +72,25 @@ SHOW CREATE TABLE t9; create database mysqltest; --error 1,1 -create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="/this-dir-does-not-exist"; +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam index directory="/this-dir-does-not-exist"; # temporarily disabled as it returns different result in the embedded server -# --error ER_WRONG_ARGUMENTS, ER_WRONG_ARGUMENTS -# create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="not-hard-path"; +--error ER_WRONG_TABLE_NAME +create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam index directory="not-hard-path"; # Should fail becasue the file t9.MYI already exist in 'run' --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1,1,ER_UNKNOWN_ERROR -eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="$MYSQLTEST_VARDIR/run"; +eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam index directory="$MYSQLTEST_VARDIR/run"; # Should fail becasue the file t9.MYD already exist in 'tmp' --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1,1 -eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="$MYSQLTEST_VARDIR/tmp"; +eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) +engine=myisam data directory="$MYSQLTEST_VARDIR/tmp"; # Check moving table t9 from default database to mysqltest; # In this case the symlinks should be removed. diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index d31939ed3dd..b766c1c7dc6 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -779,7 +779,7 @@ SET @@myisam_mmap_size= 500M; --echo # Bug #52315: utc_date() crashes when system time > year 2037 --echo # ---error 0, ER_UNKNOWN_ERROR +--error 0, ER_WRONG_VALUE_FOR_VAR SET TIMESTAMP=2*1024*1024*1024; --echo #Should not crash --disable_result_log diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 725e7da43db..e641efbdecc 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -1,4 +1,4 @@ -# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public @@ -806,7 +806,6 @@ fun:my_malloc fun:_lf_dynarray_lvalue fun:_lf_pinbox_get_pins - fun:lf_pinbox_get_pins } { @@ -836,3 +835,45 @@ fun:lf_hash_search } +{ + Bug 59874 Valgrind warning in InnoDB compression code + Memcheck:Cond + fun:* + fun:* + fun:deflate + fun:btr_store_big_rec_extern_fields_func + fun:row_ins_index_entry_low + fun:row_ins_index_entry + fun:row_ins_index_entry_step + fun:row_ins + fun:row_ins_step + fun:row_insert_for_mysql +} + +{ + In page0zip.c we have already checked that the memory is initialized before calling deflate() + Memcheck:Cond + fun:* + fun:* + fun:deflate + fun:page_zip_compress +} + +{ + In page0zip.c we have already checked that the memory is initialized before calling deflate() + Memcheck:Cond + fun:* + fun:* + fun:deflate + fun:page_zip_compress_deflate +} + +{ + Bug 59875 Valgrind warning in buf0buddy.c + Memcheck:Addr1 + fun:mach_read_from_4 + fun:buf_buddy_relocate + fun:buf_buddy_free_low + fun:buf_buddy_free + fun:buf_LRU_block_remove_hashed_page +} diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index e184c8308fc..6e81b644bae 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c index 01b3b912aae..63280f40f2a 100644 --- a/mysys/my_getsystime.c +++ b/mysys/my_getsystime.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc +/* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/plugin/auth/test_plugin.c b/plugin/auth/test_plugin.c index 161062d5b6c..d38b2782285 100644 --- a/plugin/auth/test_plugin.c +++ b/plugin/auth/test_plugin.c @@ -82,6 +82,36 @@ static struct st_mysql_auth auth_test_handler= auth_test_plugin }; +/** + dialog test plugin mimicking the ordinary auth mechanism. Used to test the clear text plugin API +*/ +static int auth_cleartext_plugin(MYSQL_PLUGIN_VIO *vio, + MYSQL_SERVER_AUTH_INFO *info) +{ + unsigned char *pkt; + int pkt_len; + + /* read the password */ + if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) + return CR_ERROR; + + info->password_used= PASSWORD_USED_YES; + + /* fail if the password is wrong */ + if (strcmp((const char *) pkt, info->auth_string)) + return CR_ERROR; + + return CR_OK; +} + + +static struct st_mysql_auth auth_cleartext_handler= +{ + MYSQL_AUTHENTICATION_INTERFACE_VERSION, + "mysql_clear_password", /* requires the clear text plugin */ + auth_cleartext_plugin +}; + mysql_declare_plugin(test_plugin) { MYSQL_AUTHENTICATION_PLUGIN, @@ -96,9 +126,24 @@ mysql_declare_plugin(test_plugin) NULL, NULL, NULL +}, +{ + MYSQL_AUTHENTICATION_PLUGIN, + &auth_cleartext_handler, + "cleartext_plugin_server", + "Georgi Kodinov", + "cleartext plugin API test plugin", + PLUGIN_LICENSE_GPL, + NULL, + NULL, + 0x0100, + NULL, + NULL, + NULL } mysql_declare_plugin_end; + /********************* CLIENT SIDE ***************************************/ /* client plugin used for testing the plugin API diff --git a/regex/my_regex.h b/regex/my_regex.h index 0d1cedf5430..30896e29b91 100644 --- a/regex/my_regex.h +++ b/regex/my_regex.h @@ -28,6 +28,7 @@ typedef struct { /* === regcomp.c === */ +typedef int (*my_regex_stack_check_t)(); extern int my_regcomp(my_regex_t *, const char *, int, CHARSET_INFO *charset); #define REG_BASIC 0000 #define REG_EXTENDED 0001 @@ -76,7 +77,8 @@ extern void my_regfree(my_regex_t *); /* === reginit.c === */ -extern void my_regex_init(CHARSET_INFO *cs); /* Should be called for multithread progs */ +/* Should be called for multithread progs */ +extern void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func); extern void my_regex_end(void); /* If one wants a clean end */ #ifdef __cplusplus diff --git a/regex/regcomp.c b/regex/regcomp.c index b41a1ae6da9..6e2d2511fc1 100644 --- a/regex/regcomp.c +++ b/regex/regcomp.c @@ -31,6 +31,9 @@ struct parse { CHARSET_INFO *charset; /* for ctype things */ }; +/* Check if there is enough stack space for recursion. */ +my_regex_stack_check_t my_regex_enough_mem_in_stack= NULL; + #include "regcomp.ih" static char nuls[10]; /* place to point scanner in event of error */ @@ -117,7 +120,7 @@ CHARSET_INFO *charset; # define GOODFLAGS(f) ((f)&~REG_DUMP) #endif - my_regex_init(charset); /* Init cclass if neaded */ + my_regex_init(charset, NULL); /* Init cclass if neaded */ preg->charset=charset; cflags = GOODFLAGS(cflags); if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) @@ -222,7 +225,15 @@ int stop; /* character this ERE should end at */ /* do a bunch of concatenated expressions */ conc = HERE(); while (MORE() && (c = PEEK()) != '|' && c != stop) - p_ere_exp(p); + { + if (my_regex_enough_mem_in_stack && + my_regex_enough_mem_in_stack()) + { + SETERROR(REG_ESPACE); + return; + } + p_ere_exp(p); + } if(REQUIRE(HERE() != conc, REG_EMPTY)) {}/* require nonempty */ if (!EAT('|')) diff --git a/regex/reginit.c b/regex/reginit.c index 5980de24030..3d2cd64d1e7 100644 --- a/regex/reginit.c +++ b/regex/reginit.c @@ -4,10 +4,12 @@ #include <m_ctype.h> #include <m_string.h> #include "cclass.h" +#include "my_regex.h" static my_bool regex_inited=0; +extern my_regex_stack_check_t my_regex_enough_mem_in_stack; -void my_regex_init(CHARSET_INFO *cs) +void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func) { char buff[CCLASS_LAST][256]; int count[CCLASS_LAST]; @@ -16,6 +18,7 @@ void my_regex_init(CHARSET_INFO *cs) if (!regex_inited) { regex_inited=1; + my_regex_enough_mem_in_stack= func; bzero((uchar*) &count,sizeof(count)); for (i=1 ; i<= 255; i++) @@ -74,6 +77,7 @@ void my_regex_end() int i; for (i=0; i < CCLASS_LAST ; i++) free((char*) cclasses[i].chars); + my_regex_enough_mem_in_stack= NULL; regex_inited=0; } } diff --git a/sql-common/client.c b/sql-common/client.c index 3b7fc11a537..0ff03f6609b 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2261,6 +2261,7 @@ typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t; static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int); static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); +static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); static auth_plugin_t native_password_client_plugin= { @@ -2294,10 +2295,27 @@ static auth_plugin_t old_password_client_plugin= old_password_auth_client }; +static auth_plugin_t clear_password_client_plugin= +{ + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION, + "mysql_clear_password", + "Georgi Kodinov", + "Clear password authentication plugin", + {0,1,0}, + "GPL", + NULL, + NULL, + NULL, + NULL, + clear_password_auth_client +}; + struct st_mysql_client_plugin *mysql_client_builtins[]= { (struct st_mysql_client_plugin *)&native_password_client_plugin, (struct st_mysql_client_plugin *)&old_password_client_plugin, + (struct st_mysql_client_plugin *)&clear_password_client_plugin, 0 }; @@ -4271,3 +4289,20 @@ static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) DBUG_RETURN(CR_OK); } + +/** + The main function of the mysql_clear_password authentication plugin. +*/ + +static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) +{ + int res; + + /* send password in clear text */ + res= vio->write_packet(vio, (const unsigned char *) mysql->passwd, + strlen(mysql->passwd) + 1); + + return res ? CR_ERROR : CR_OK; +} + + diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 38384600fc1..39eee57a1c0 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -992,7 +992,7 @@ my_system_gmt_sec(const MYSQL_TIME *t_src, long *my_timezone, with unsigned time_t tmp+= shift*86400L might result in a number, larger then TIMESTAMP_MAX_VALUE, so another check will work. */ - if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE)) + if (!IS_TIME_T_VALID_FOR_TIMESTAMP(tmp)) tmp= 0; return (my_time_t) tmp; diff --git a/sql/field.cc b/sql/field.cc index 50db2da97e4..01c4459c06c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9073,6 +9073,7 @@ void Create_field::create_length_to_internal_length(void) case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_GEOMETRY: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: case MYSQL_TYPE_VARCHAR: diff --git a/sql/filesort.cc b/sql/filesort.cc index f888206f730..cf5334cd87f 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -324,8 +324,24 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, } } if (error) - my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT), - MYF(ME_ERROR+ME_WAITTANG)); + { + DBUG_ASSERT(thd->is_error()); + my_printf_error(ER_FILSORT_ABORT, + "%s: %s", + MYF(ME_ERROR + ME_WAITTANG), + ER_THD(thd, ER_FILSORT_ABORT), + thd->stmt_da->message()); + + if (global_system_variables.log_warnings > 1) + { + sql_print_warning("%s, host: %s, user: %s, thread: %lu, query: %-.4096s", + ER_THD(thd, ER_FILSORT_ABORT), + thd->security_ctx->host_or_ip, + &thd->security_ctx->priv_user[0], + (ulong) thd->thread_id, + thd->query()); + } + } else statistic_add(thd->status_var.filesort_rows, (ulong) records, &LOCK_status); @@ -369,6 +385,9 @@ static char **make_char_array(char **old_pos, register uint fields, char *char_pos; DBUG_ENTER("make_char_array"); + DBUG_EXECUTE_IF("make_char_array_fail", + DBUG_SET("+d,simulate_out_of_memory");); + if (old_pos || (old_pos= (char**) my_malloc((uint) fields*(length+sizeof(char*)), my_flag))) diff --git a/sql/handler.cc b/sql/handler.cc index 783e4d9ae20..f7690c28827 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/item.h b/sql/item.h index 058aa10bb2d..fc203f03e79 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,7 +1,7 @@ #ifndef ITEM_INCLUDED #define ITEM_INCLUDED -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/item_func.h b/sql/item_func.h index 937907c9404..e60effc352c 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1,7 +1,7 @@ #ifndef ITEM_FUNC_INCLUDED #define ITEM_FUNC_INCLUDED -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 6145f72b665..c5c1eae2d39 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1,7 +1,7 @@ #ifndef ITEM_GEOFUNC_INCLUDED #define ITEM_GEOFUNC_INCLUDED -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 24d8d354670..e26f9b4467a 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1,7 +1,7 @@ #ifndef ITEM_STRFUNC_INCLUDED #define ITEM_STRFUNC_INCLUDED -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 @@ -361,7 +361,9 @@ public: { maybe_null=1; /* 9 = MAX ((8- (arg_len % 8)) + 1) */ - max_length = args[0]->max_length - 9; + max_length= args[0]->max_length; + if (max_length >= 9U) + max_length-= 9U; } const char *func_name() const { return "des_decrypt"; } }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0fd526184c4..adfa1ea66f0 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -556,24 +556,27 @@ Item *Item_sum::set_arg(uint i, THD *thd, Item *new_val) int Item_sum::set_aggregator(Aggregator::Aggregator_type aggregator) { - if (aggr) + /* + Dependent subselects may be executed multiple times, making + set_aggregator to be called multiple times. The aggregator type + will be the same, but it needs to be reset so that it is + reevaluated with the new dependent data. + This function may also be called multiple times during query optimization. + In this case, the type may change, so we delete the old aggregator, + and create a new one. + */ + if (aggr && aggregator == aggr->Aggrtype()) { - /* - Dependent subselects may be executed multiple times, making - set_aggregator to be called multiple times. The aggregator type - will be the same, but it needs to be reset so that it is - reevaluated with the new dependent data. - */ - DBUG_ASSERT(aggregator == aggr->Aggrtype()); aggr->clear(); return FALSE; } + + delete aggr; switch (aggregator) { case Aggregator::DISTINCT_AGGREGATOR: aggr= new Aggregator_distinct(this); break; - case Aggregator::SIMPLE_AGGREGATOR: aggr= new Aggregator_simple(this); break; diff --git a/sql/item_sum.h b/sql/item_sum.h index 81e5e10fffa..4e2334b6c3b 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -461,10 +461,9 @@ public: */ virtual void no_rows_in_result() { - if (!aggr) - set_aggregator(with_distinct ? - Aggregator::DISTINCT_AGGREGATOR : - Aggregator::SIMPLE_AGGREGATOR); + set_aggregator(with_distinct ? + Aggregator::DISTINCT_AGGREGATOR : + Aggregator::SIMPLE_AGGREGATOR); aggregator_clear(); } virtual void make_unique() { force_copy_fields= TRUE; } @@ -515,11 +514,10 @@ public: quick_group= with_distinct ? 0 : 1; } - /** + /* Set the type of aggregation : DISTINCT or not. - Called when the final determination is done about the aggregation - type and the object is about to be used. + May be called multiple times. */ int set_aggregator(Aggregator::Aggregator_type aggregator); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 622d6a76e50..b8c6b1d38e4 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -1,7 +1,7 @@ #ifndef ITEM_TIMEFUNC_INCLUDED #define ITEM_TIMEFUNC_INCLUDED -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/log.cc b/sql/log.cc index 7ab4b6b4a61..9a7a1699b62 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 188ed7c6885..c81d8bd75e2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2879,6 +2879,19 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]); #endif +#ifndef EMBEDDED_LIBRARY +static +int +check_enough_stack_size() +{ + uchar stack_top; + + return check_stack_overrun(current_thd, STACK_MIN_SIZE, + &stack_top); +} +#endif + + /** Initialize one of the global date/time format variables. @@ -3080,12 +3093,6 @@ static int init_common_variables() max_system_variables.pseudo_thread_id= (ulong)~0; server_start_time= flush_status_time= my_time(0); - /* TODO: remove this when my_time_t is 64 bit compatible */ - if (server_start_time >= (time_t) MY_TIME_T_MAX) - { - sql_print_error("This MySQL server doesn't support dates later then 2038"); - return 1; - } rpl_filter= new Rpl_filter; binlog_filter= new Rpl_filter; @@ -3124,6 +3131,13 @@ static int init_common_variables() */ mysql_bin_log.init_pthread_objects(); + /* TODO: remove this when my_time_t is 64 bit compatible */ + if (!IS_TIME_T_VALID_FOR_TIMESTAMP(server_start_time)) + { + sql_print_error("This MySQL server doesn't support dates later then 2038"); + return 1; + } + if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0) { strmake(glob_hostname, STRING_WITH_LEN("localhost")); @@ -3339,7 +3353,11 @@ static int init_common_variables() if (item_create_init()) return 1; item_init(); - my_regex_init(&my_charset_latin1); +#ifndef EMBEDDED_LIBRARY + my_regex_init(&my_charset_latin1, check_enough_stack_size); +#else + my_regex_init(&my_charset_latin1, NULL); +#endif /* Process a comma-separated character set list and choose the first available character set. This is mostly for diff --git a/sql/net_serv.cc b/sql/net_serv.cc index d60e2051ccd..e2cc32015b1 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/protocol.cc b/sql/protocol.cc index 03b151e4346..c50861d73a0 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011 Oracle and/or its affiliates. All rights reserved. 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 @@ -543,9 +543,10 @@ bool Protocol::send_ok(uint server_status, uint statement_warn_count, const char *message) { DBUG_ENTER("Protocol::send_ok"); - - DBUG_RETURN(net_send_ok(thd, server_status, statement_warn_count, - affected_rows, last_insert_id, message)); + const bool retval= + net_send_ok(thd, server_status, statement_warn_count, + affected_rows, last_insert_id, message); + DBUG_RETURN(retval); } @@ -558,8 +559,8 @@ bool Protocol::send_ok(uint server_status, uint statement_warn_count, bool Protocol::send_eof(uint server_status, uint statement_warn_count) { DBUG_ENTER("Protocol::send_eof"); - - DBUG_RETURN(net_send_eof(thd, server_status, statement_warn_count)); + const bool retval= net_send_eof(thd, server_status, statement_warn_count); + DBUG_RETURN(retval); } @@ -573,8 +574,8 @@ bool Protocol::send_error(uint sql_errno, const char *err_msg, const char *sql_state) { DBUG_ENTER("Protocol::send_error"); - - DBUG_RETURN(net_send_error_packet(thd, sql_errno, err_msg, sql_state)); + const bool retval= net_send_error_packet(thd, sql_errno, err_msg, sql_state); + DBUG_RETURN(retval); } diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index b0dc4d9195b..a8b0c27d115 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -897,7 +897,7 @@ ER_OUT_OF_SORTMEMORY HY001 S1001 cze "M-Bálo paměti pro třídění. Zvyšte velikost třídícího bufferu" dan "Ikke mere sorteringshukommelse. Øg sorteringshukommelse (sort buffer size) for serveren" nla "Geen geheugen om te sorteren. Verhoog de server sort buffer size" - eng "Out of sort memory; increase server sort buffer size" + eng "Out of sort memory, consider increasing server sort buffer size" jps "Out of sort memory. sort buffer size が足りないようです.", est "Mälu sai sorteerimisel otsa. Suurenda MySQL-i sorteerimispuhvrit" fre "Manque de mémoire pour le tri. Augmentez-la." @@ -907,10 +907,10 @@ ER_OUT_OF_SORTMEMORY HY001 S1001 ita "Memoria per gli ordinamenti esaurita. Incrementare il 'sort_buffer' al demone" jpn "Out of sort memory. sort buffer size が足りないようです." kor "Out of sort memory. daemon sort buffer의 크기를 증가시키세요" - nor "Ikke mer sorteringsminne. Øk sorteringsminnet (sort buffer size) for tjenesten" - norwegian-ny "Ikkje meir sorteringsminne. Auk sorteringsminnet (sorteringsbffer storleik) for tenesten" + nor "Ikke mer sorteringsminne. Vurder å øke sorteringsminnet (sort buffer size) for tjenesten" + norwegian-ny "Ikkje meir sorteringsminne. Vurder å auke sorteringsminnet (sorteringsbuffer storleik) for tenesten" pol "Zbyt mało pamięci dla sortowania. Zwiększ wielko?ć bufora demona dla sortowania" - por "Sem memória para ordenação. Aumente tamanho do 'buffer' de ordenação" + por "Não há memória suficiente para ordenação. Considere aumentar o tamanho do retentor (buffer) de ordenação." rum "Out of memory pentru sortare. Largeste marimea buffer-ului pentru sortare in daemon (sort buffer size)" rus "Недостаточно памяти для сортировки. Увеличьте размер буфера сортировки на сервере" serbian "Nema memorije za sortiranje. Povećajte veličinu sort buffer-a MySQL server-u" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 882b1a2e8a7..8b6cc2caf10 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/sql_class.h b/sql/sql_class.h index 8b05497388e..137a0c48ead 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2280,7 +2280,7 @@ public: /*TODO: this will be obsolete when we have support for 64 bit my_time_t */ inline bool is_valid_time() { - return (start_time < (time_t) MY_TIME_T_MAX); + return (IS_TIME_T_VALID_FOR_TIMESTAMP(start_time)); } void set_time_after_lock() { utime_after_lock= my_micro_time(); } ulonglong current_utime() { return my_micro_time(); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 0b463ff1202..4475e087163 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -979,7 +979,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; - if ((changed && error <= 0) || + if (error <= 0 || thd->transaction.stmt.modified_non_trans_table || was_insert_delayed) { diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 0b4f956dd7f..5c2c0bb95d6 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1,4 +1,4 @@ -/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4cc49daf3fe..bc0cca4d887 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -676,8 +676,11 @@ impossible position"; file */ if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) goto err; + + my_off_t prev_pos= pos; while (!(error = Log_event::read_log_event(&log, packet, log_lock))) { + prev_pos= my_b_tell(&log); #ifndef DBUG_OFF if (max_binlog_dump_events && !left_events--) { @@ -767,8 +770,13 @@ impossible position"; here we were reading binlog that was not closed properly (as a result of a crash ?). treat any corruption as EOF */ - if (binlog_can_be_corrupted && error != LOG_READ_MEM) + if (binlog_can_be_corrupted && + error != LOG_READ_MEM && error != LOG_READ_EOF) + { + my_b_seek(&log, prev_pos); error=LOG_READ_EOF; + } + /* TODO: now that we are logging the offset, check to make sure the recorded offset and the actual match. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fdce2510df4..3d073cf777e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 @@ -3365,26 +3365,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, eq_func is NEVER true when num_values > 1 */ if (!eq_func) - { - /* - Additional optimization: if we're processing - "t.key BETWEEN c1 AND c1" then proceed as if we were processing - "t.key = c1". - TODO: This is a very limited fix. A more generic fix is possible. - There are 2 options: - A) Make equality propagation code be able to handle BETWEEN - (including cases like t1.key BETWEEN t2.key AND t3.key) - B) Make range optimizer to infer additional "t.key = c" equalities - and use them in equality propagation process (see details in - OptimizerKBAndTodo) - */ - if ((cond->functype() != Item_func::BETWEEN) || - ((Item_func_between*) cond)->negated || - !value[0]->eq(value[1], field->binary())) - return; - eq_func= TRUE; - } - + return; if (field->result_type() == STRING_RESULT) { if ((*value)->result_type() != STRING_RESULT) @@ -3580,9 +3561,65 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, case Item_func::OPTIMIZE_KEY: { Item **values; - // BETWEEN, IN, NE - if (is_local_field (cond_func->key_item()) && - !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) + /* + Build list of possible keys for 'a BETWEEN low AND high'. + It is handled similar to the equivalent condition + 'a >= low AND a <= high': + */ + if (cond_func->functype() == Item_func::BETWEEN) + { + Item_field *field_item; + bool equal_func= FALSE; + uint num_values= 2; + values= cond_func->arguments(); + + bool binary_cmp= (values[0]->real_item()->type() == Item::FIELD_ITEM) + ? ((Item_field*)values[0]->real_item())->field->binary() + : TRUE; + + /* + Additional optimization: If 'low = high': + Handle as if the condition was "t.key = low". + */ + if (!((Item_func_between*)cond_func)->negated && + values[1]->eq(values[2], binary_cmp)) + { + equal_func= TRUE; + num_values= 1; + } + + /* + Append keys for 'field <cmp> value[]' if the + condition is of the form:: + '<field> BETWEEN value[1] AND value[2]' + */ + if (is_local_field (values[0])) + { + field_item= (Item_field *) (values[0]->real_item()); + add_key_equal_fields(key_fields, *and_level, cond_func, + field_item, equal_func, &values[1], + num_values, usable_tables, sargables); + } + /* + Append keys for 'value[0] <cmp> field' if the + condition is of the form: + 'value[0] BETWEEN field1 AND field2' + */ + for (uint i= 1; i <= num_values; i++) + { + if (is_local_field (values[i])) + { + field_item= (Item_field *) (values[i]->real_item()); + add_key_equal_fields(key_fields, *and_level, cond_func, + field_item, equal_func, values, + 1, usable_tables, sargables); + } + } + } // if ( ... Item_func::BETWEEN) + + // IN, NE + else if (is_local_field (cond_func->key_item()) && + !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { values= cond_func->arguments()+1; if (cond_func->functype() == Item_func::NE_FUNC && @@ -3596,21 +3633,6 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, cond_func->argument_count()-1, usable_tables, sargables); } - if (cond_func->functype() == Item_func::BETWEEN) - { - values= cond_func->arguments(); - for (uint i= 1 ; i < cond_func->argument_count() ; i++) - { - Item_field *field_item; - if (is_local_field (cond_func->arguments()[i])) - { - field_item= (Item_field *) (cond_func->arguments()[i]->real_item()); - add_key_equal_fields(key_fields, *and_level, cond_func, - field_item, 0, values, 1, usable_tables, - sargables); - } - } - } break; } case Item_func::OPTIMIZE_OP: @@ -11745,17 +11767,40 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, first_unmatched->found= 1; for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) { - if (tab->table->reginfo.not_exists_optimize) - return NESTED_LOOP_NO_MORE_ROWS; /* Check all predicates that has just been activated. */ /* Actually all predicates non-guarded by first_unmatched->found will be re-evaluated again. It could be fixed, but, probably, it's not worth doing now. */ + /* + not_exists_optimize has been created from a + select_cond containing 'is_null'. This 'is_null' + predicate is still present on any 'tab' with + 'not_exists_optimize'. Furthermore, the usual rules + for condition guards also applies for + 'not_exists_optimize' -> When 'is_null==false' we + know all cond. guards are open and we can apply + the 'not_exists_optimize'. + */ + DBUG_ASSERT(!(tab->table->reginfo.not_exists_optimize && + !tab->select_cond)); + if (tab->select_cond && !tab->select_cond->val_int()) { /* The condition attached to table tab is false */ + + if (tab->table->reginfo.not_exists_optimize) + { + /* + When not_exists_optimize is set: No need to further + explore more rows of 'tab' for this partial result. + Any found 'tab' matches are known to evaluate to 'false'. + Returning .._NO_MORE_ROWS will skip rem. 'tab' rows. + */ + return NESTED_LOOP_NO_MORE_ROWS; + } + if (tab == join_tab) found= 0; else @@ -13574,12 +13619,14 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, { int ref_key; uint ref_key_parts; - int order_direction; + int order_direction= 0; uint used_key_parts; TABLE *table=tab->table; SQL_SELECT *select=tab->select; key_map usable_keys; QUICK_SELECT_I *save_quick= 0; + int best_key= -1; + DBUG_ENTER("test_if_skip_sort_order"); LINT_INIT(ref_key_parts); @@ -13683,13 +13730,14 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, new_ref_key_map.clear_all(); // Force the creation of quick select new_ref_key_map.set_bit(new_ref_key); // only for new_ref_key. + select->quick= 0; if (select->test_quick_select(tab->join->thd, new_ref_key_map, 0, (tab->join->select_options & OPTION_FOUND_ROWS) ? HA_POS_ERROR : tab->join->unit->select_limit_cnt,0) <= 0) - DBUG_RETURN(0); + goto use_filesort; } ref_key= new_ref_key; } @@ -13704,7 +13752,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, uint best_key_parts= 0; uint saved_best_key_parts= 0; int best_key_direction= 0; - int best_key= -1; JOIN *join= tab->join; ha_rows table_records= table->file->stats.records; @@ -13724,72 +13771,21 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, tab->join->tables > tab->join->const_tables + 1) && ((unsigned) best_key != table->s->primary_key || !table->file->primary_key_is_clustered())) - DBUG_RETURN(0); + goto use_filesort; if (best_key >= 0) { - bool quick_created= FALSE; if (table->quick_keys.is_set(best_key) && best_key != ref_key) { key_map map; map.clear_all(); // Force the creation of quick select map.set_bit(best_key); // only best_key. - quick_created= - select->test_quick_select(join->thd, map, 0, - join->select_options & OPTION_FOUND_ROWS ? - HA_POS_ERROR : - join->unit->select_limit_cnt, - 0) > 0; - } - if (!no_changes) - { - /* - If ref_key used index tree reading only ('Using index' in EXPLAIN), - and best_key doesn't, then revert the decision. - */ - if (!table->covering_keys.is_set(best_key)) - table->set_keyread(FALSE); - if (!quick_created) - { - tab->index= best_key; - tab->read_first_record= best_key_direction > 0 ? - join_read_first:join_read_last; - tab->type=JT_NEXT; // Read with index_first(), index_next() - if (select && select->quick) - { - delete select->quick; - select->quick= 0; - } - if (table->covering_keys.is_set(best_key)) - table->set_keyread(TRUE); - table->file->ha_index_or_rnd_end(); - if (join->select_options & SELECT_DESCRIBE) - { - tab->ref.key= -1; - tab->ref.key_parts= 0; - if (select_limit < table_records) - tab->limit= select_limit; - } - } - else if (tab->type != JT_ALL) - { - /* - We're about to use a quick access to the table. - We need to change the access method so as the quick access - method is actually used. - */ - DBUG_ASSERT(tab->select->quick); - tab->type=JT_ALL; - tab->use_quick=1; - tab->ref.key= -1; - tab->ref.key_parts=0; // Don't use ref key. - tab->read_first_record= join_init_read_record; - if (tab->is_using_loose_index_scan()) - join->tmp_table_param.precomputed_group_by= TRUE; - /* - TODO: update the number of records in join->best_positions[tablenr] - */ - } + select->quick= 0; + select->test_quick_select(join->thd, map, 0, + join->select_options & OPTION_FOUND_ROWS ? + HA_POS_ERROR : + join->unit->select_limit_cnt, + 0); } order_direction= best_key_direction; /* @@ -13802,10 +13798,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, saved_best_key_parts : best_key_parts; } else - DBUG_RETURN(0); + goto use_filesort; } check_reverse_order: + DBUG_ASSERT(order_direction != 0); + if (order_direction == -1) // If ORDER BY ... DESC { if (select && select->quick) @@ -13814,9 +13812,10 @@ check_reverse_order: Don't reverse the sort order, if it's already done. (In some cases test_if_order_by_key() can be called multiple times */ - if (!select->quick->reverse_sorted()) + if (select->quick->reverse_sorted()) + goto skipped_filesort; + else { - QUICK_SELECT_I *tmp; int quick_type= select->quick->get_type(); if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE || quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || @@ -13824,37 +13823,128 @@ check_reverse_order: quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) { tab->limit= 0; - select->quick= save_quick; - DBUG_RETURN(0); // Use filesort + goto use_filesort; // Use filesort } - - /* ORDER BY range_key DESC */ - tmp= select->quick->make_reverse(used_key_parts); - if (!tmp) - { - select->quick= save_quick; - tab->limit= 0; - DBUG_RETURN(0); // Reverse sort not supported - } - select->set_quick(tmp); } } - else if (tab->type != JT_NEXT && tab->type != JT_REF_OR_NULL && - tab->ref.key >= 0 && tab->ref.key_parts <= used_key_parts) + } + + /* + Update query plan with access pattern for doing + ordered access according to what we have decided + above. + */ + if (!no_changes) // We are allowed to update QEP + { + if (best_key >= 0) { - /* - SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC + bool quick_created= + (select && select->quick && select->quick!=save_quick); - Use a traversal function that starts by reading the last row - with key part (A) and then traverse the index backwards. + /* + If ref_key used index tree reading only ('Using index' in EXPLAIN), + and best_key doesn't, then revert the decision. */ - tab->read_first_record= join_read_last_key; - tab->read_record.read_record= join_read_prev_same; + if (!table->covering_keys.is_set(best_key)) + table->set_keyread(FALSE); + if (!quick_created) + { + if (select) // Throw any existing quick select + select->quick= 0; // Cleanup either reset to save_quick, + // or 'delete save_quick' + tab->index= best_key; + tab->read_first_record= order_direction > 0 ? + join_read_first:join_read_last; + tab->type=JT_NEXT; // Read with index_first(), index_next() + + if (table->covering_keys.is_set(best_key)) + table->set_keyread(TRUE); + table->file->ha_index_or_rnd_end(); + if (tab->join->select_options & SELECT_DESCRIBE) + { + tab->ref.key= -1; + tab->ref.key_parts= 0; + if (select_limit < table->file->stats.records) + tab->limit= select_limit; + } + } + else if (tab->type != JT_ALL) + { + /* + We're about to use a quick access to the table. + We need to change the access method so as the quick access + method is actually used. + */ + DBUG_ASSERT(tab->select->quick); + tab->type=JT_ALL; + tab->use_quick=1; + tab->ref.key= -1; + tab->ref.key_parts=0; // Don't use ref key. + tab->read_first_record= join_init_read_record; + if (tab->is_using_loose_index_scan()) + tab->join->tmp_table_param.precomputed_group_by= TRUE; + /* + TODO: update the number of records in join->best_positions[tablenr] + */ + } + } // best_key >= 0 + + if (order_direction == -1) // If ORDER BY ... DESC + { + if (select && select->quick) + { + /* ORDER BY range_key DESC */ + QUICK_SELECT_I *tmp= select->quick->make_reverse(used_key_parts); + if (!tmp) + { + tab->limit= 0; + goto use_filesort; // Reverse sort failed -> filesort + } + if (select->quick == save_quick) + save_quick= 0; // make_reverse() consumed it + select->set_quick(tmp); + } + else if (tab->type != JT_NEXT && tab->type != JT_REF_OR_NULL && + tab->ref.key >= 0 && tab->ref.key_parts <= used_key_parts) + { + /* + SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC + + Use a traversal function that starts by reading the last row + with key part (A) and then traverse the index backwards. + */ + tab->read_first_record= join_read_last_key; + tab->read_record.read_record= join_read_prev_same; + } } + else if (select && select->quick) + select->quick->sorted= 1; + + } // QEP has been modified + + /* + Cleanup: + We may have both a 'select->quick' and 'save_quick' (original) + at this point. Delete the one that we wan't use. + */ + +skipped_filesort: + // Keep current (ordered) select->quick + if (select && save_quick != select->quick) + { + delete save_quick; + save_quick= NULL; } - else if (select && select->quick) - select->quick->sorted= 1; DBUG_RETURN(1); + +use_filesort: + // Restore original save_quick + if (select && select->quick != save_quick) + { + delete select->quick; + select->quick= save_quick; + } + DBUG_RETURN(0); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f965c9371f0..abef175ab55 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 9b4543bf636..17b8056a165 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc +/* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 68bb77d467f..ce1dcb4a33c 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2430,17 +2430,17 @@ static ulonglong read_timestamp(THD *thd) static bool check_timestamp(sys_var *self, THD *thd, set_var *var) { - time_t val; + longlong val; if (!var->value) return FALSE; - val= (time_t) var->save_result.ulonglong_value; - if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX) + val= (longlong) var->save_result.ulonglong_value; + if (val != 0 && // this is how you set the default value + (val < TIMESTAMP_MIN_VALUE || val > TIMESTAMP_MAX_VALUE)) { - my_message(ER_UNKNOWN_ERROR, - "This version of MySQL doesn't support dates later than 2038", - MYF(0)); + char buf[64]; + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "timestamp", llstr(val, buf)); return TRUE; } return FALSE; diff --git a/sql/table.cc b/sql/table.cc index fae044f334a..0ce7d7427d3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 diff --git a/sql/unireg.h b/sql/unireg.h index b897c887c89..1bf956efb4f 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -1,7 +1,7 @@ #ifndef UNIREG_INCLUDED #define UNIREG_INCLUDED -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 @@ -56,8 +56,6 @@ typedef struct st_ha_create_information HA_CREATE_INFO; #define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, X) : ER_DEFAULT(X)) -#define ERRMAPP 1 /* Errormap f|r my_error */ - #define ME_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH) #define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH) #define MYF_RW MYF(MY_WME+MY_NABP) /* Vid my_read & my_write */ diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index ff82372b52b..2e544c0552a 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -981,7 +981,7 @@ btr_page_reorganize_low( log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); #ifndef UNIV_HOTBACKUP - temp_block = buf_block_alloc(buf_pool, 0); + temp_block = buf_block_alloc(buf_pool); #else /* !UNIV_HOTBACKUP */ ut_ad(block == back_block1); temp_block = back_block2; diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index a5856479147..ff9b1835a53 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -111,6 +111,18 @@ can be released by page reorganize, then it is reorganized */ /*--------------------------------------*/ #define BTR_BLOB_HDR_SIZE 8 /*!< Size of a BLOB part header, in bytes */ + +/** Estimated table level stats from sampled value. +@param value sampled stats +@param index index being sampled +@param sample number of sampled rows +@param ext_size external stored data size +@param not_empty table not empty +@return estimated table wide stats from sampled value */ +#define BTR_TABLE_STATS_FROM_SAMPLE(value, index, sample, ext_size, not_empty)\ + (((value) * (ib_int64_t) index->stat_n_leaf_pages \ + + (sample) - 1 + (ext_size) + (not_empty)) / ((sample) + (ext_size))) + /* @} */ #endif /* !UNIV_HOTBACKUP */ @@ -185,7 +197,7 @@ static ulint btr_rec_get_externally_stored_len( /*==============================*/ - rec_t* rec, /*!< in: record */ + const rec_t* rec, /*!< in: record */ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ #endif /* !UNIV_HOTBACKUP */ @@ -1874,8 +1886,8 @@ btr_cur_update_in_place( NOT call it if index is secondary */ if (!dict_index_is_clust(index) - || row_upd_changes_ord_field_binary(NULL, NULL, - index, update)) { + || row_upd_changes_ord_field_binary(index, update, thr, + NULL, NULL)) { /* Remove possible hash index pointer to this record */ btr_search_update_hash_on_delete(cursor); @@ -3479,9 +3491,54 @@ btr_estimate_n_rows_in_range( } /*******************************************************************//** +Record the number of non_null key values in a given index for +each n-column prefix of the index where n < dict_index_get_n_unique(index). +The estimates are eventually stored in the array: +index->stat_n_non_null_key_vals. */ +static +void +btr_record_not_null_field_in_rec( +/*=============================*/ + rec_t* rec, /*!< in: physical record */ + ulint n_unique, /*!< in: dict_index_get_n_unique(index), + number of columns uniquely determine + an index entry */ + const ulint* offsets, /*!< in: rec_get_offsets(rec, index), + its size could be for all fields or + that of "n_unique" */ + ib_int64_t* n_not_null) /*!< in/out: array to record number of + not null rows for n-column prefix */ +{ + ulint i; + + ut_ad(rec_offs_n_fields(offsets) >= n_unique); + + if (n_not_null == NULL) { + return; + } + + for (i = 0; i < n_unique; i++) { + ulint rec_len; + byte* field; + + field = rec_get_nth_field(rec, offsets, i, &rec_len); + + if (rec_len != UNIV_SQL_NULL) { + n_not_null[i]++; + } else { + /* Break if we hit the first NULL value */ + break; + } + } +} + +/*******************************************************************//** Estimates the number of different key values in a given index, for each n-column prefix of the index where n <= dict_index_get_n_unique(index). -The estimates are stored in the array index->stat_n_diff_key_vals. */ +The estimates are stored in the array index->stat_n_diff_key_vals. +If innodb_stats_method is "nulls_ignored", we also record the number of +non-null values for each prefix and store the estimates in +array index->stat_n_non_null_key_vals. */ UNIV_INTERN void btr_estimate_number_of_different_key_vals( @@ -3495,6 +3552,8 @@ btr_estimate_number_of_different_key_vals( ulint matched_fields; ulint matched_bytes; ib_int64_t* n_diff; + ib_int64_t* n_not_null; + ibool stats_null_not_equal; ullint n_sample_pages; /* number of pages to sample */ ulint not_empty_flag = 0; ulint total_external_size = 0; @@ -3503,16 +3562,43 @@ btr_estimate_number_of_different_key_vals( ullint add_on; mtr_t mtr; mem_heap_t* heap = NULL; - ulint offsets_rec_[REC_OFFS_NORMAL_SIZE]; - ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE]; - ulint* offsets_rec = offsets_rec_; - ulint* offsets_next_rec= offsets_next_rec_; - rec_offs_init(offsets_rec_); - rec_offs_init(offsets_next_rec_); + ulint* offsets_rec = NULL; + ulint* offsets_next_rec = NULL; n_cols = dict_index_get_n_unique(index); - n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t)); + heap = mem_heap_create((sizeof *n_diff + sizeof *n_not_null) + * (n_cols + 1) + + dict_index_get_n_fields(index) + * (sizeof *offsets_rec + + sizeof *offsets_next_rec)); + + n_diff = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t)); + + n_not_null = NULL; + + /* Check srv_innodb_stats_method setting, and decide whether we + need to record non-null value and also decide if NULL is + considered equal (by setting stats_null_not_equal value) */ + switch (srv_innodb_stats_method) { + case SRV_STATS_NULLS_IGNORED: + n_not_null = mem_heap_zalloc(heap, (n_cols + 1) + * sizeof *n_not_null); + /* fall through */ + + case SRV_STATS_NULLS_UNEQUAL: + /* for both SRV_STATS_NULLS_IGNORED and SRV_STATS_NULLS_UNEQUAL + case, we will treat NULLs as unequal value */ + stats_null_not_equal = TRUE; + break; + + case SRV_STATS_NULLS_EQUAL: + stats_null_not_equal = FALSE; + break; + + default: + ut_error; + } /* It makes no sense to test more pages than are contained in the index, thus we lower the number if it is too high */ @@ -3529,7 +3615,6 @@ btr_estimate_number_of_different_key_vals( /* We sample some pages in the index to get an estimate */ for (i = 0; i < n_sample_pages; i++) { - rec_t* supremum; mtr_start(&mtr); btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr); @@ -3542,18 +3627,25 @@ btr_estimate_number_of_different_key_vals( page = btr_cur_get_page(&cursor); - supremum = page_get_supremum_rec(page); rec = page_rec_get_next(page_get_infimum_rec(page)); - if (rec != supremum) { + if (!page_rec_is_supremum(rec)) { not_empty_flag = 1; offsets_rec = rec_get_offsets(rec, index, offsets_rec, ULINT_UNDEFINED, &heap); + + if (n_not_null) { + btr_record_not_null_field_in_rec( + rec, n_cols, offsets_rec, n_not_null); + } } - while (rec != supremum) { + while (!page_rec_is_supremum(rec)) { rec_t* next_rec = page_rec_get_next(rec); - if (next_rec == supremum) { + if (page_rec_is_supremum(next_rec)) { + total_external_size += + btr_rec_get_externally_stored_len( + rec, offsets_rec); break; } @@ -3561,11 +3653,13 @@ btr_estimate_number_of_different_key_vals( matched_bytes = 0; offsets_next_rec = rec_get_offsets(next_rec, index, offsets_next_rec, - n_cols, &heap); + ULINT_UNDEFINED, + &heap); cmp_rec_rec_with_match(rec, next_rec, offsets_rec, offsets_next_rec, - index, &matched_fields, + index, stats_null_not_equal, + &matched_fields, &matched_bytes); for (j = matched_fields + 1; j <= n_cols; j++) { @@ -3575,6 +3669,12 @@ btr_estimate_number_of_different_key_vals( n_diff[j]++; } + if (n_not_null) { + btr_record_not_null_field_in_rec( + next_rec, n_cols, offsets_next_rec, + n_not_null); + } + total_external_size += btr_rec_get_externally_stored_len( rec, offsets_rec); @@ -3609,10 +3709,6 @@ btr_estimate_number_of_different_key_vals( } } - offsets_rec = rec_get_offsets(rec, index, offsets_rec, - ULINT_UNDEFINED, &heap); - total_external_size += btr_rec_get_externally_stored_len( - rec, offsets_rec); mtr_commit(&mtr); } @@ -3626,13 +3722,9 @@ btr_estimate_number_of_different_key_vals( for (j = 0; j <= n_cols; j++) { index->stat_n_diff_key_vals[j] - = ((n_diff[j] - * (ib_int64_t)index->stat_n_leaf_pages - + n_sample_pages - 1 - + total_external_size - + not_empty_flag) - / (n_sample_pages - + total_external_size)); + = BTR_TABLE_STATS_FROM_SAMPLE( + n_diff[j], index, n_sample_pages, + total_external_size, not_empty_flag); /* If the tree is small, smaller than 10 * n_sample_pages + total_external_size, then @@ -3651,45 +3743,81 @@ btr_estimate_number_of_different_key_vals( } index->stat_n_diff_key_vals[j] += add_on; - } - mem_free(n_diff); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); + /* Update the stat_n_non_null_key_vals[] with our + sampled result. stat_n_non_null_key_vals[] is created + and initialized to zero in dict_index_add_to_cache(), + along with stat_n_diff_key_vals[] array */ + if (n_not_null != NULL && (j < n_cols)) { + index->stat_n_non_null_key_vals[j] = + BTR_TABLE_STATS_FROM_SAMPLE( + n_not_null[j], index, n_sample_pages, + total_external_size, not_empty_flag); + } } + + mem_heap_free(heap); } /*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/ /***********************************************************//** +Gets the offset of the pointer to the externally stored part of a field. +@return offset of the pointer to the externally stored part */ +static +ulint +btr_rec_get_field_ref_offs( +/*=======================*/ + const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ + ulint n) /*!< in: index of the external field */ +{ + ulint field_ref_offs; + ulint local_len; + + ut_a(rec_offs_nth_extern(offsets, n)); + field_ref_offs = rec_get_nth_field_offs(offsets, n, &local_len); + ut_a(local_len != UNIV_SQL_NULL); + ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); + + return(field_ref_offs + local_len - BTR_EXTERN_FIELD_REF_SIZE); +} + +/** Gets a pointer to the externally stored part of a field. +@param rec record +@param offsets rec_get_offsets(rec) +@param n index of the externally stored field +@return pointer to the externally stored part */ +#define btr_rec_get_field_ref(rec, offsets, n) \ + ((rec) + btr_rec_get_field_ref_offs(offsets, n)) + +/***********************************************************//** Gets the externally stored size of a record, in units of a database page. @return externally stored part, in units of a database page */ static ulint btr_rec_get_externally_stored_len( /*==============================*/ - rec_t* rec, /*!< in: record */ + const rec_t* rec, /*!< in: record */ const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ { ulint n_fields; - byte* data; - ulint local_len; - ulint extern_len; ulint total_extern_len = 0; ulint i; ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec)); + + if (!rec_offs_any_extern(offsets)) { + return(0); + } + n_fields = rec_offs_n_fields(offsets); for (i = 0; i < n_fields; i++) { if (rec_offs_nth_extern(offsets, i)) { - data = rec_get_nth_field(rec, offsets, i, &local_len); - - local_len -= BTR_EXTERN_FIELD_REF_SIZE; - - extern_len = mach_read_from_4(data + local_len - + BTR_EXTERN_LEN + 4); + ulint extern_len = mach_read_from_4( + btr_rec_get_field_ref(rec, offsets, i) + + BTR_EXTERN_LEN + 4); total_extern_len += ut_calc_align(extern_len, UNIV_PAGE_SIZE); @@ -3719,7 +3847,7 @@ btr_cur_set_ownership_of_extern_field( ulint byte_val; data = rec_get_nth_field(rec, offsets, i, &local_len); - + ut_ad(rec_offs_nth_extern(offsets, i)); ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); local_len -= BTR_EXTERN_FIELD_REF_SIZE; @@ -3729,6 +3857,9 @@ btr_cur_set_ownership_of_extern_field( if (val) { byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG); } else { +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ut_a(!(byte_val & BTR_EXTERN_OWNER_FLAG)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ byte_val = byte_val | BTR_EXTERN_OWNER_FLAG; } @@ -3946,13 +4077,12 @@ btr_blob_free( && buf_block_get_space(block) == space && buf_block_get_page_no(block) == page_no) { - if (buf_LRU_free_block(&block->page, all, NULL) - != BUF_LRU_FREED + if (buf_LRU_free_block(&block->page, all) != BUF_LRU_FREED && all && block->page.zip.data) { /* Attempt to deallocate the uncompressed page if the whole block cannot be deallocted. */ - buf_LRU_free_block(&block->page, FALSE, NULL); + buf_LRU_free_block(&block->page, FALSE); } } @@ -3968,8 +4098,8 @@ file segment of the index tree. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ UNIV_INTERN ulint -btr_store_big_rec_extern_fields( -/*============================*/ +btr_store_big_rec_extern_fields_func( +/*=================================*/ dict_index_t* index, /*!< in: index of rec; the index tree MUST be X-latched */ buf_block_t* rec_block, /*!< in/out: block containing rec */ @@ -3978,11 +4108,17 @@ btr_store_big_rec_extern_fields( the "external storage" flags in offsets will not correspond to rec when this function returns */ - big_rec_t* big_rec_vec, /*!< in: vector containing fields +#ifdef UNIV_DEBUG + mtr_t* local_mtr, /*!< in: mtr containing the + latch to rec and to the tree */ +#endif /* UNIV_DEBUG */ +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ibool update_in_place,/*! in: TRUE if the record is updated + in place (not delete+insert) */ +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + const big_rec_t*big_rec_vec) /*!< in: vector containing fields to be stored externally */ - mtr_t* local_mtr __attribute__((unused))) /*!< in: mtr - containing the latch to rec and to the - tree */ + { ulint rec_page_no; byte* field_ref; @@ -4000,6 +4136,7 @@ btr_store_big_rec_extern_fields( z_stream c_stream; ut_ad(rec_offs_validate(rec, index, offsets)); + ut_ad(rec_offs_any_extern(offsets)); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); @@ -4031,21 +4168,37 @@ btr_store_big_rec_extern_fields( ut_a(err == Z_OK); } +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + /* All pointers to externally stored columns in the record + must either be zero or they must be pointers to inherited + columns, owned by this record or an earlier record version. */ + for (i = 0; i < rec_offs_n_fields(offsets); i++) { + if (!rec_offs_nth_extern(offsets, i)) { + continue; + } + field_ref = btr_rec_get_field_ref(rec, offsets, i); + + ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG)); + /* Either this must be an update in place, + or the BLOB must be inherited, or the BLOB pointer + must be zero (will be written in this function). */ + ut_a(update_in_place + || (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG) + || !memcmp(field_ref, field_ref_zero, + BTR_EXTERN_FIELD_REF_SIZE)); + } +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ /* We have to create a file segment to the tablespace for each field and put the pointer to the field in rec */ for (i = 0; i < big_rec_vec->n_fields; i++) { - ut_ad(rec_offs_nth_extern(offsets, - big_rec_vec->fields[i].field_no)); - { - ulint local_len; - field_ref = rec_get_nth_field( - rec, offsets, big_rec_vec->fields[i].field_no, - &local_len); - ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); - local_len -= BTR_EXTERN_FIELD_REF_SIZE; - field_ref += local_len; - } + field_ref = btr_rec_get_field_ref( + rec, offsets, big_rec_vec->fields[i].field_no); +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + /* A zero BLOB pointer should have been initially inserted. */ + ut_a(!memcmp(field_ref, field_ref_zero, + BTR_EXTERN_FIELD_REF_SIZE)); +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ extern_len = big_rec_vec->fields[i].len; UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data, extern_len); @@ -4327,6 +4480,23 @@ next_zip_page: mem_heap_free(heap); } +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + /* All pointers to externally stored columns in the record + must be valid. */ + for (i = 0; i < rec_offs_n_fields(offsets); i++) { + if (!rec_offs_nth_extern(offsets, i)) { + continue; + } + + field_ref = btr_rec_get_field_ref(rec, offsets, i); + + /* The pointer must not be zero. */ + ut_a(0 != memcmp(field_ref, field_ref_zero, + BTR_EXTERN_FIELD_REF_SIZE)); + /* The column must not be disowned by this record. */ + ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG)); + } +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ return(DB_SUCCESS); } @@ -4349,6 +4519,7 @@ btr_check_blob_fil_page_type( if (UNIV_UNLIKELY(type != FIL_PAGE_TYPE_BLOB)) { ulint flags = fil_space_get_flags(space_id); +#ifndef UNIV_DEBUG /* Improve debug test coverage */ if (UNIV_LIKELY ((flags & DICT_TF_FORMAT_MASK) == DICT_TF_FORMAT_51)) { /* Old versions of InnoDB did not initialize @@ -4357,6 +4528,7 @@ btr_check_blob_fil_page_type( a BLOB page that is in Antelope format.*/ return; } +#endif /* !UNIV_DEBUG */ ut_print_timestamp(stderr); fprintf(stderr, @@ -4406,23 +4578,13 @@ btr_free_externally_stored_field( ulint page_no; ulint next_page_no; mtr_t mtr; -#ifdef UNIV_DEBUG + ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains_page(local_mtr, field_ref, MTR_MEMO_PAGE_X_FIX)); ut_ad(!rec || rec_offs_validate(rec, index, offsets)); - - if (rec) { - ulint local_len; - const byte* f = rec_get_nth_field(rec, offsets, - i, &local_len); - ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); - local_len -= BTR_EXTERN_FIELD_REF_SIZE; - f += local_len; - ut_ad(f == field_ref); - } -#endif /* UNIV_DEBUG */ + ut_ad(!rec || field_ref == btr_rec_get_field_ref(rec, offsets, i)); if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) { @@ -4585,13 +4747,8 @@ btr_rec_free_externally_stored_fields( for (i = 0; i < n_fields; i++) { if (rec_offs_nth_extern(offsets, i)) { - ulint len; - byte* data - = rec_get_nth_field(rec, offsets, i, &len); - ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); - btr_free_externally_stored_field( - index, data + len - BTR_EXTERN_FIELD_REF_SIZE, + index, btr_rec_get_field_ref(rec, offsets, i), rec, offsets, page_zip, i, rb_ctx, mtr); } } diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c index 8f5f9b839b5..d192ee7c132 100644 --- a/storage/innobase/btr/btr0sea.c +++ b/storage/innobase/btr/btr0sea.c @@ -151,7 +151,7 @@ btr_search_check_free_space_in_heap(void) be enough free space in the hash table. */ if (heap->free_block == NULL) { - buf_block_t* block = buf_block_alloc(NULL, 0); + buf_block_t* block = buf_block_alloc(NULL); rw_lock_x_lock(&btr_search_latch); diff --git a/storage/innobase/buf/buf0buddy.c b/storage/innobase/buf/buf0buddy.c index 787b4e652a0..75ba832c7e5 100644 --- a/storage/innobase/buf/buf0buddy.c +++ b/storage/innobase/buf/buf0buddy.c @@ -327,7 +327,7 @@ buf_buddy_alloc_low( /* Try replacing an uncompressed page in the buffer pool. */ buf_pool_mutex_exit(buf_pool); - block = buf_LRU_get_free_block(buf_pool, 0); + block = buf_LRU_get_free_block(buf_pool); *lru = TRUE; buf_pool_mutex_enter(buf_pool); diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 3ff69d8fd1b..e825dcd79f9 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -416,9 +416,9 @@ UNIV_INTERN buf_block_t* buf_block_alloc( /*============*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - ulint zip_size) /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ + buf_pool_t* buf_pool) /*!< in/out: buffer pool instance, + or NULL for round-robin selection + of the buffer pool */ { buf_block_t* block; ulint index; @@ -431,7 +431,7 @@ buf_block_alloc( buf_pool = buf_pool_from_array(index); } - block = buf_LRU_get_free_block(buf_pool, zip_size); + block = buf_LRU_get_free_block(buf_pool); buf_block_set_state(block, BUF_BLOCK_MEMORY); @@ -865,9 +865,9 @@ buf_block_init( block->modify_clock = 0; -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG block->page.file_page_was_freed = FALSE; -#endif /* UNIV_DEBUG_FILE_ACCESSES */ +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ block->check_index_page_at_flush = FALSE; block->index = NULL; @@ -1623,7 +1623,7 @@ shrink_again: buf_LRU_make_block_old(&block->page); dirty++; - } else if (buf_LRU_free_block(&block->page, TRUE, NULL) + } else if (buf_LRU_free_block(&block->page, TRUE) != BUF_LRU_FREED) { nonfree++; } @@ -2229,7 +2229,7 @@ buf_page_peek_if_search_hashed( return(is_hashed); } -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. This function should be called when we free a file page and want the @@ -2252,6 +2252,8 @@ buf_page_set_file_page_was_freed( if (bpage) { ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage)); + /* bpage->file_page_was_freed can already hold + when this code is invoked from dict_drop_index_tree() */ bpage->file_page_was_freed = TRUE; } @@ -2289,7 +2291,7 @@ buf_page_reset_file_page_was_freed( return(bpage); } -#endif /* UNIV_DEBUG_FILE_ACCESSES */ +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ /********************************************************************//** Get read access to a compressed page (usually of type @@ -2366,8 +2368,7 @@ err_exit: mutex_enter(block_mutex); /* Discard the uncompressed page frame if possible. */ - if (buf_LRU_free_block(bpage, FALSE, NULL) - == BUF_LRU_FREED) { + if (buf_LRU_free_block(bpage, FALSE) == BUF_LRU_FREED) { mutex_exit(block_mutex); goto lookup; @@ -2391,7 +2392,7 @@ got_block: buf_page_set_accessed_make_young(bpage, access_time); -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(!bpage->file_page_was_freed); #endif @@ -2883,7 +2884,7 @@ wait_until_unfixed: buf_pool_mutex_exit(buf_pool); mutex_exit(&buf_pool->zip_mutex); - block = buf_LRU_get_free_block(buf_pool, 0); + block = buf_LRU_get_free_block(buf_pool); ut_a(block); buf_pool_mutex_enter(buf_pool); @@ -3013,8 +3014,7 @@ wait_until_unfixed: /* Try to evict the block from the buffer pool, to use the insert buffer (change buffer) as much as possible. */ - if (buf_LRU_free_block(&block->page, TRUE, NULL) - == BUF_LRU_FREED) { + if (buf_LRU_free_block(&block->page, TRUE) == BUF_LRU_FREED) { mutex_exit(&block->mutex); if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) { /* Set the watch, as it would have @@ -3060,7 +3060,7 @@ wait_until_unfixed: buf_page_set_accessed_make_young(&block->page, access_time); -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(!block->page.file_page_was_freed); #endif @@ -3219,7 +3219,7 @@ buf_page_optimistic_get( ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(block->page.file_page_was_freed == FALSE); #endif if (UNIV_UNLIKELY(!access_time)) { @@ -3331,7 +3331,7 @@ buf_page_get_known_nowait( ut_a(block->page.buf_fix_count > 0); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(block->page.file_page_was_freed == FALSE); #endif @@ -3417,9 +3417,9 @@ buf_page_try_get_func( ut_a(block->page.buf_fix_count > 0); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(block->page.file_page_was_freed == FALSE); -#endif /* UNIV_DEBUG_FILE_ACCESSES */ +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); buf_pool->stat.n_page_gets++; @@ -3448,9 +3448,9 @@ buf_page_init_low( bpage->newest_modification = 0; bpage->oldest_modification = 0; HASH_INVALIDATE(bpage, hash); -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG bpage->file_page_was_freed = FALSE; -#endif /* UNIV_DEBUG_FILE_ACCESSES */ +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ } /********************************************************************//** @@ -3588,7 +3588,7 @@ buf_page_init_for_read( && UNIV_LIKELY(!recv_recovery_is_on())) { block = NULL; } else { - block = buf_LRU_get_free_block(buf_pool, 0); + block = buf_LRU_get_free_block(buf_pool); ut_ad(block); ut_ad(buf_pool_from_block(block) == buf_pool); } @@ -3794,7 +3794,7 @@ buf_page_create( ut_ad(mtr->state == MTR_ACTIVE); ut_ad(space || !zip_size); - free_block = buf_LRU_get_free_block(buf_pool, 0); + free_block = buf_LRU_get_free_block(buf_pool); fold = buf_page_address_fold(space, offset); @@ -3809,9 +3809,9 @@ buf_page_create( #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(space, offset) == 0); #endif -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG block->page.file_page_was_freed = FALSE; -#endif /* UNIV_DEBUG_FILE_ACCESSES */ +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ /* Page can be found in buf_pool */ buf_pool_mutex_exit(buf_pool); diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index d819782ac9d..910e8386a71 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -603,7 +603,7 @@ buf_LRU_free_from_unzip_LRU_list( ut_ad(block->page.in_LRU_list); mutex_enter(&block->mutex); - freed = buf_LRU_free_block(&block->page, FALSE, NULL); + freed = buf_LRU_free_block(&block->page, FALSE); mutex_exit(&block->mutex); switch (freed) { @@ -666,7 +666,7 @@ buf_LRU_free_from_common_LRU_list( mutex_enter(block_mutex); accessed = buf_page_is_accessed(bpage); - freed = buf_LRU_free_block(bpage, TRUE, NULL); + freed = buf_LRU_free_block(bpage, TRUE); mutex_exit(block_mutex); switch (freed) { @@ -858,9 +858,7 @@ UNIV_INTERN buf_block_t* buf_LRU_get_free_block( /*===================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - ulint zip_size) /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ + buf_pool_t* buf_pool) /*!< in/out: buffer pool instance */ { buf_block_t* block = NULL; ibool freed; @@ -936,31 +934,11 @@ loop: /* If there is a block in the free list, take it */ block = buf_LRU_get_free_only(buf_pool); - if (block) { + buf_pool_mutex_exit(buf_pool); + if (block) { ut_ad(buf_pool_from_block(block) == buf_pool); - -#ifdef UNIV_DEBUG - block->page.zip.m_start = -#endif /* UNIV_DEBUG */ - block->page.zip.m_end = - block->page.zip.m_nonempty = - block->page.zip.n_blobs = 0; - - if (UNIV_UNLIKELY(zip_size)) { - ibool lru; - page_zip_set_size(&block->page.zip, zip_size); - - block->page.zip.data = buf_buddy_alloc( - buf_pool, zip_size, &lru); - - UNIV_MEM_DESC(block->page.zip.data, zip_size, block); - } else { - page_zip_set_size(&block->page.zip, 0); - block->page.zip.data = NULL; - } - - buf_pool_mutex_exit(buf_pool); + memset(&block->page.zip, 0, sizeof block->page.zip); if (started_monitor) { srv_print_innodb_monitor = mon_value_was; @@ -972,8 +950,6 @@ loop: /* If no block was in the free list, search from the end of the LRU list and try to free a block there */ - buf_pool_mutex_exit(buf_pool); - freed = buf_LRU_search_and_free_block(buf_pool, n_iterations); if (freed > 0) { @@ -1456,12 +1432,8 @@ enum buf_lru_free_block_status buf_LRU_free_block( /*===============*/ buf_page_t* bpage, /*!< in: block to be freed */ - ibool zip, /*!< in: TRUE if should remove also the + ibool zip) /*!< in: TRUE if should remove also the compressed page of an uncompressed page */ - ibool* buf_pool_mutex_released) - /*!< in: pointer to a variable that will - be assigned TRUE if buf_pool_mutex - was temporarily released, or NULL */ { buf_page_t* b = NULL; buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); @@ -1638,10 +1610,6 @@ alloc: b->io_fix = BUF_IO_READ; } - if (buf_pool_mutex_released) { - *buf_pool_mutex_released = TRUE; - } - buf_pool_mutex_exit(buf_pool); mutex_exit(block_mutex); diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 4b21a51ded9..ebc7747640e 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -1689,6 +1689,12 @@ undo_size_ok: new_index->heap, (1 + dict_index_get_n_unique(new_index)) * sizeof(ib_int64_t)); + + new_index->stat_n_non_null_key_vals = mem_heap_zalloc( + new_index->heap, + (1 + dict_index_get_n_unique(new_index)) + * sizeof(*new_index->stat_n_non_null_key_vals)); + /* Give some sensible values to stat_n_... in case we do not calculate statistics quickly enough */ @@ -4319,6 +4325,10 @@ dict_update_statistics( for (i = dict_index_get_n_unique(index); i; ) { index->stat_n_diff_key_vals[i--] = 1; } + + memset(index->stat_n_non_null_key_vals, 0, + (1 + dict_index_get_n_unique(index)) + * sizeof(*index->stat_n_non_null_key_vals)); } index = dict_table_get_next_index(index); diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 3252e85b358..3561e7220ab 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -1552,7 +1552,7 @@ err_len: "InnoDB: in InnoDB data dictionary" " has unknown type %lx.\n", (ulong) flags); - return(NULL); + return("incorrect flags in SYS_TABLES"); } } else { flags = 0; diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index 5bf5411bc6a..3f09732a676 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -3435,9 +3435,9 @@ fseg_free_page( fseg_free_page_low(seg_inode, space, zip_size, page, mtr); -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG buf_page_set_file_page_was_freed(space, page); -#endif +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ } /**********************************************************************//** @@ -3503,13 +3503,13 @@ fseg_free_extent( fsp_free_extent(space, zip_size, page, mtr); -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG for (i = 0; i < FSP_EXTENT_SIZE; i++) { buf_page_set_file_page_was_freed(space, first_page_in_extent + i); } -#endif +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ } /**********************************************************************//** diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ed83a83b2e7..daeaca90aec 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -172,6 +172,25 @@ static char* internal_innobase_data_file_path = NULL; static char* innodb_version_str = (char*) INNODB_VERSION_STR; +/** Possible values for system variable "innodb_stats_method". The values +are defined the same as its corresponding MyISAM system variable +"myisam_stats_method"(see "myisam_stats_method_names"), for better usability */ +static const char* innodb_stats_method_names[] = { + "nulls_equal", + "nulls_unequal", + "nulls_ignored", + NullS +}; + +/** Used to define an enumerate type of the system variable innodb_stats_method. +This is the same as "myisam_stats_method_typelib" */ +static TYPELIB innodb_stats_method_typelib = { + array_elements(innodb_stats_method_names) - 1, + "innodb_stats_method_typelib", + innodb_stats_method_names, + NULL +}; + /* The following counter is used to convey information to InnoDB about server activity: in selects it is not sensible to call srv_active_wake_master_thread after each fetch or search, we only do @@ -7722,6 +7741,65 @@ innobase_get_mysql_key_number_for_index( return(0); } + +/*********************************************************************//** +Calculate Record Per Key value. Need to exclude the NULL value if +innodb_stats_method is set to "nulls_ignored" +@return estimated record per key value */ +static +ha_rows +innodb_rec_per_key( +/*===============*/ + dict_index_t* index, /*!< in: dict_index_t structure */ + ulint i, /*!< in: the column we are + calculating rec per key */ + ha_rows records) /*!< in: estimated total records */ +{ + ha_rows rec_per_key; + + ut_ad(i < dict_index_get_n_unique(index)); + + /* Note the stat_n_diff_key_vals[] stores the diff value with + n-prefix indexing, so it is always stat_n_diff_key_vals[i + 1] */ + if (index->stat_n_diff_key_vals[i + 1] == 0) { + + rec_per_key = records; + } else if (srv_innodb_stats_method == SRV_STATS_NULLS_IGNORED) { + ib_int64_t num_null; + + /* Number of rows with NULL value in this + field */ + num_null = records - index->stat_n_non_null_key_vals[i]; + + /* In theory, index->stat_n_non_null_key_vals[i] + should always be less than the number of records. + Since this is statistics value, the value could + have slight discrepancy. But we will make sure + the number of null values is not a negative number. */ + num_null = (num_null < 0) ? 0 : num_null; + + /* If the number of NULL values is the same as or + large than that of the distinct values, we could + consider that the table consists mostly of NULL value. + Set rec_per_key to 1. */ + if (index->stat_n_diff_key_vals[i + 1] <= num_null) { + rec_per_key = 1; + } else { + /* Need to exclude rows with NULL values from + rec_per_key calculation */ + rec_per_key = (ha_rows)( + (records - num_null) + / (index->stat_n_diff_key_vals[i + 1] + - num_null)); + } + } else { + rec_per_key = (ha_rows) + (records / index->stat_n_diff_key_vals[i + 1]); + } + + return(rec_per_key); +} + /*********************************************************************//** Returns statistics information of the table to the MySQL interpreter, in various fields of the handle object. */ @@ -7955,13 +8033,8 @@ ha_innobase::info_low( break; } - if (index->stat_n_diff_key_vals[j + 1] == 0) { - - rec_per_key = stats.records; - } else { - rec_per_key = (ha_rows)(stats.records / - index->stat_n_diff_key_vals[j + 1]); - } + rec_per_key = innodb_rec_per_key( + index, j, stats.records); /* Since MySQL seems to favor table scans too much over index searches, we pretend @@ -11184,6 +11257,13 @@ static MYSQL_SYSVAR_STR(change_buffering, innobase_change_buffering, innodb_change_buffering_validate, innodb_change_buffering_update, "all"); +static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method, + PLUGIN_VAR_RQCMDARG, + "Specifies how InnoDB index statistics collection code should " + "treat NULLs. Possible values are NULLS_EQUAL (default), " + "NULLS_UNEQUAL and NULLS_IGNORED", + NULL, NULL, SRV_STATS_NULLS_EQUAL, &innodb_stats_method_typelib); + #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug, PLUGIN_VAR_RQCMDARG, @@ -11240,6 +11320,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(stats_on_metadata), MYSQL_SYSVAR(stats_sample_pages), MYSQL_SYSVAR(adaptive_hash_index), + MYSQL_SYSVAR(stats_method), MYSQL_SYSVAR(replication_delay), MYSQL_SYSVAR(status_file), MYSQL_SYSVAR(strict_mode), diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 0cec0318bf4..93d152bfb74 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -2276,9 +2276,9 @@ ibuf_remove_free_page(void) fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, IBUF_SPACE_ID, page_no, &mtr); -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG buf_page_reset_file_page_was_freed(IBUF_SPACE_ID, page_no); -#endif +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ ibuf_enter(); @@ -2322,9 +2322,9 @@ ibuf_remove_free_page(void) ibuf_bitmap_page_set_bits( bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr); -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG buf_page_set_file_page_was_freed(IBUF_SPACE_ID, page_no); -#endif +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ mtr_commit(&mtr); ibuf_exit(); @@ -2585,23 +2585,6 @@ ibuf_contract_ext( if (UNIV_UNLIKELY(ibuf->empty) && UNIV_LIKELY(!srv_shutdown_state)) { -ibuf_is_empty: - -#if 0 /* TODO */ - if (srv_shutdown_state) { - /* If the insert buffer becomes empty during - shutdown, note it in the system tablespace. */ - - trx_sys_set_ibuf_format(TRX_SYS_IBUF_EMPTY); - } - - /* TO DO: call trx_sys_set_ibuf_format() at startup - and whenever ibuf_use is changed to allow buffered - delete-marking or deleting. Never downgrade the - stamped format except when the insert buffer becomes - empty. */ -#endif - return(0); } @@ -2631,7 +2614,7 @@ ibuf_is_empty: mtr_commit(&mtr); btr_pcur_close(&pcur); - goto ibuf_is_empty; + return(0); } sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur), diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index cb65c6bfab7..be918439f59 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -466,7 +466,10 @@ btr_estimate_n_rows_in_range( /*******************************************************************//** Estimates the number of different key values in a given index, for each n-column prefix of the index where n <= dict_index_get_n_unique(index). -The estimates are stored in the array index->stat_n_diff_key_vals. */ +The estimates are stored in the array index->stat_n_diff_key_vals. +If innodb_stats_method is nulls_ignored, we also record the number of +non-null values for each prefix and stored the estimates in +array index->stat_n_non_null_key_vals. */ UNIV_INTERN void btr_estimate_number_of_different_key_vals( @@ -497,8 +500,8 @@ file segment of the index tree. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ UNIV_INTERN ulint -btr_store_big_rec_extern_fields( -/*============================*/ +btr_store_big_rec_extern_fields_func( +/*=================================*/ dict_index_t* index, /*!< in: index of rec; the index tree MUST be X-latched */ buf_block_t* rec_block, /*!< in/out: block containing rec */ @@ -507,10 +510,42 @@ btr_store_big_rec_extern_fields( the "external storage" flags in offsets will not correspond to rec when this function returns */ - big_rec_t* big_rec_vec, /*!< in: vector containing fields +#ifdef UNIV_DEBUG + mtr_t* local_mtr, /*!< in: mtr containing the + latch to rec and to the tree */ +#endif /* UNIV_DEBUG */ +#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG + ibool update_in_place,/*! in: TRUE if the record is updated + in place (not delete+insert) */ +#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ + const big_rec_t*big_rec_vec) /*!< in: vector containing fields to be stored externally */ - mtr_t* local_mtr); /*!< in: mtr containing the latch to - rec and to the tree */ + __attribute__((nonnull)); + +/** Stores the fields in big_rec_vec to the tablespace and puts pointers to +them in rec. The extern flags in rec will have to be set beforehand. +The fields are stored on pages allocated from leaf node +file segment of the index tree. +@param index in: clustered index; MUST be X-latched by mtr +@param b in/out: block containing rec; MUST be X-latched by mtr +@param rec in/out: clustered index record +@param offsets in: rec_get_offsets(rec, index); + the "external storage" flags in offsets will not be adjusted +@param mtr in: mini-transaction that holds x-latch on index and b +@param upd in: TRUE if the record is updated in place (not delete+insert) +@param big in: vector containing fields to be stored externally +@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ +#ifdef UNIV_DEBUG +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big) +#elif defined UNIV_BLOB_LIGHT_DEBUG +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big) +#else +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big) +#endif + /*******************************************************************//** Frees the space in an externally stored field to the file space management if the field in data is owned the externally stored field, diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 46cae25f0f5..dbd5adee0cc 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -276,9 +276,9 @@ UNIV_INTERN buf_block_t* buf_block_alloc( /*============*/ - buf_pool_t* buf_pool, /*!< buffer pool instance */ - ulint zip_size); /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ + buf_pool_t* buf_pool); /*!< in: buffer pool instance, + or NULL for round-robin selection + of the buffer pool */ /********************************************************************//** Frees a buffer block which does not contain a file page. */ UNIV_INLINE @@ -480,7 +480,7 @@ buf_reset_check_index_page_at_flush( /*================================*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: page number */ -#ifdef UNIV_DEBUG_FILE_ACCESSES +#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. This function should be called when we free a file page and want the @@ -505,7 +505,7 @@ buf_page_reset_file_page_was_freed( /*===============================*/ ulint space, /*!< in: space id */ ulint offset); /*!< in: page number */ -#endif /* UNIV_DEBUG_FILE_ACCESSES */ +#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ /********************************************************************//** Reads the freed_page_clock of a buffer block. @return freed_page_clock */ @@ -1403,11 +1403,11 @@ struct buf_page_struct{ 0 if the block was never accessed in the buffer pool */ /* @} */ -# ifdef UNIV_DEBUG_FILE_ACCESSES +# if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ibool file_page_was_freed; /*!< this is set to TRUE when fsp frees a page in buffer pool */ -# endif /* UNIV_DEBUG_FILE_ACCESSES */ +# endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ }; diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 7bcec633d9c..9b150188b03 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -111,12 +111,9 @@ enum buf_lru_free_block_status buf_LRU_free_block( /*===============*/ buf_page_t* bpage, /*!< in: block to be freed */ - ibool zip, /*!< in: TRUE if should remove also the + ibool zip) /*!< in: TRUE if should remove also the compressed page of an uncompressed page */ - ibool* buf_pool_mutex_released); - /*!< in: pointer to a variable that will - be assigned TRUE if buf_pool->mutex - was temporarily released, or NULL */ + __attribute__((nonnull)); /******************************************************************//** Try to free a replaceable block. @return TRUE if found and freed */ @@ -153,9 +150,8 @@ UNIV_INTERN buf_block_t* buf_LRU_get_free_block( /*===================*/ - buf_pool_t* buf_pool, /*!< in: preferred buffer pool */ - ulint zip_size); /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ + buf_pool_t* buf_pool) /*!< in/out: buffer pool instance */ + __attribute__((nonnull,warn_unused_result)); /******************************************************************//** Puts a block back to the free list. */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 7526e4dc8dc..5757b79d3ed 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -376,6 +376,12 @@ struct dict_index_struct{ dict_get_n_unique(index); we periodically calculate new estimates */ + ib_int64_t* stat_n_non_null_key_vals; + /* approximate number of non-null key values + for this index, for each column where + n < dict_get_n_unique(index); This + is used when innodb_stats_method is + "nulls_ignored". */ ulint stat_index_size; /*!< approximate index size in database pages */ diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 0a9edfbfe70..687209575c9 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -33,11 +33,6 @@ typedef struct dict_index_struct dict_index_t; typedef struct dict_table_struct dict_table_t; typedef struct dict_foreign_struct dict_foreign_t; -/* A cluster object is a table object with the type field set to -DICT_CLUSTERED */ - -typedef dict_table_t dict_cluster_t; - typedef struct ind_node_struct ind_node_t; typedef struct tab_node_struct tab_node_t; diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h index 2f751a38864..a908521c9f7 100644 --- a/storage/innobase/include/rem0cmp.h +++ b/storage/innobase/include/rem0cmp.h @@ -165,6 +165,10 @@ cmp_rec_rec_with_match( const ulint* offsets1,/*!< in: rec_get_offsets(rec1, index) */ const ulint* offsets2,/*!< in: rec_get_offsets(rec2, index) */ dict_index_t* index, /*!< in: data dictionary index */ + ibool nulls_unequal, + /* in: TRUE if this is for index statistics + cardinality estimation, and innodb_stats_method + is "nulls_unequal" or "nulls_ignored" */ ulint* matched_fields, /*!< in/out: number of already completely matched fields; when the function returns, contains the value the for current diff --git a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic index 39ef5f4fba3..63415fe7837 100644 --- a/storage/innobase/include/rem0cmp.ic +++ b/storage/innobase/include/rem0cmp.ic @@ -87,5 +87,5 @@ cmp_rec_rec( ulint match_b = 0; return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index, - &match_f, &match_b)); + FALSE, &match_f, &match_b)); } diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 9c2e003c609..c275c1da78e 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -280,19 +280,29 @@ NOTE: we compare the fields as binary strings! @return TRUE if update vector changes an ordering field in the index record */ UNIV_INTERN ibool -row_upd_changes_ord_field_binary( -/*=============================*/ +row_upd_changes_ord_field_binary_func( +/*==================================*/ + dict_index_t* index, /*!< in: index of the record */ + const upd_t* update, /*!< in: update vector for the row; NOTE: the + field numbers in this MUST be clustered index + positions! */ +#ifdef UNIV_DEBUG + const que_thr_t*thr, /*!< in: query thread */ +#endif /* UNIV_DEBUG */ const dtuple_t* row, /*!< in: old value of row, or NULL if the row and the data values in update are not known when this function is called, e.g., at compile time */ - const row_ext_t*ext, /*!< NULL, or prefixes of the externally + const row_ext_t*ext) /*!< NULL, or prefixes of the externally stored columns in the old row */ - dict_index_t* index, /*!< in: index of the record */ - const upd_t* update) /*!< in: update vector for the row; NOTE: the - field numbers in this MUST be clustered index - positions! */ - __attribute__((nonnull(3,4), warn_unused_result)); + __attribute__((nonnull(1,2), warn_unused_result)); +#ifdef UNIV_DEBUG +# define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \ + row_upd_changes_ord_field_binary_func(index,update,thr,row,ext) +#else /* UNIV_DEBUG */ +# define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \ + row_upd_changes_ord_field_binary_func(index,update,row,ext) +#endif /* UNIV_DEBUG */ /***********************************************************//** Checks if an update vector changes an ordering field of an index record. This function is fast if the update vector is short or the number of ordering diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 612ff4c6e54..d600ad4a034 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -172,6 +172,11 @@ capacity. PCT_IO(5) -> returns the number of IO operations that is 5% of the max where max is srv_io_capacity. */ #define PCT_IO(p) ((ulong) (srv_io_capacity * ((double) p / 100.0))) +/* The "innodb_stats_method" setting, decides how InnoDB is going +to treat NULL value when collecting statistics. It is not defined +as enum type because the configure option takes unsigned integer type. */ +extern ulong srv_innodb_stats_method; + #ifdef UNIV_LOG_ARCHIVE extern ibool srv_log_archive_on; extern ibool srv_archive_recovery; @@ -418,6 +423,19 @@ enum { in connection with recovery */ }; +/* Alternatives for srv_innodb_stats_method, which could be changed by +setting innodb_stats_method */ +enum srv_stats_method_name_enum { + SRV_STATS_NULLS_EQUAL, /* All NULL values are treated as + equal. This is the default setting + for innodb_stats_method */ + SRV_STATS_NULLS_UNEQUAL, /* All NULL values are treated as + NOT equal. */ + SRV_STATS_NULLS_IGNORED /* NULL values are ignored */ +}; + +typedef enum srv_stats_method_name_enum srv_stats_method_name_t; + #ifndef UNIV_HOTBACKUP /** Types of threads existing in the system. */ enum srv_thread_type { diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index 5988fdfb382..9e5c96fa323 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -555,6 +555,7 @@ UNIV_INTERN void rw_lock_debug_print( /*================*/ + FILE* f, /*!< in: output stream */ rw_lock_debug_t* info); /*!< in: debug struct */ #endif /* UNIV_SYNC_DEBUG */ diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index 78a7a8c4bb0..a293d9b896e 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -141,9 +141,7 @@ struct trx_rseg_struct{ ulint id; /*!< rollback segment id == the index of its slot in the trx system file copy */ mutex_t mutex; /*!< mutex protecting the fields in this - struct except id; NOTE that the latching - order must always be kernel mutex -> - rseg mutex */ + struct except id, which is constant */ ulint space; /*!< space where the rollback segment is header is placed */ ulint zip_size;/* compressed page size of space diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index b4a4aa0ca44..83f6182c347 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -214,12 +214,12 @@ trx_recover_for_mysql( /*******************************************************************//** This function is used to find one X/Open XA distributed transaction which is in the prepared state -@return trx or NULL */ +@return trx or NULL; on match, the trx->xid will be invalidated */ UNIV_INTERN trx_t * trx_get_trx_by_xid( /*===============*/ - XID* xid); /*!< in: X/Open XA transaction identification */ + const XID* xid); /*!< in: X/Open XA transaction identifier */ /**********************************************************************//** If required, flushes the log to disk if we called trx_commit_for_mysql() with trx->flush_log_later == TRUE. diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 4ca02d30db1..a99b8306eb8 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -184,14 +184,15 @@ command. Not tested on Windows. */ debugging without UNIV_DEBUG */ #define UNIV_BUF_DEBUG /* Enable buffer pool debugging without UNIV_DEBUG */ +#define UNIV_BLOB_LIGHT_DEBUG /* Enable off-page column + debugging without UNIV_DEBUG */ #define UNIV_DEBUG /* Enable ut_ad() assertions and disable UNIV_INLINE */ #define UNIV_DEBUG_LOCK_VALIDATE /* Enable ut_ad(lock_rec_validate_page()) assertions. */ -#define UNIV_DEBUG_FILE_ACCESSES /* Debug .ibd file access - (field file_page_was_freed - in buf_page_t) */ +#define UNIV_DEBUG_FILE_ACCESSES /* Enable freed block access + debugging without UNIV_DEBUG */ #define UNIV_LRU_DEBUG /* debug the buffer pool LRU */ #define UNIV_HASH_DEBUG /* debug HASH_ macros */ #define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */ @@ -441,7 +442,7 @@ it is read or written. */ /* Use sun_prefetch when compile with Sun Studio */ # define UNIV_EXPECT(expr,value) (expr) # define UNIV_LIKELY_NULL(expr) (expr) -# define UNIV_PREFETCH_R(addr) sun_prefetch_read_many(addr) +# define UNIV_PREFETCH_R(addr) sun_prefetch_read_many((void*) addr) # define UNIV_PREFETCH_RW(addr) sun_prefetch_write_many(addr) #else /* Dummy versions of the macros */ diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c index b5a7ddbd7b2..7727760f1cd 100644 --- a/storage/innobase/mem/mem0mem.c +++ b/storage/innobase/mem/mem0mem.c @@ -347,7 +347,7 @@ mem_heap_create_block( return(NULL); } } else { - buf_block = buf_block_alloc(NULL, 0); + buf_block = buf_block_alloc(NULL); } block = (mem_block_t*) buf_block->frame; diff --git a/storage/innobase/mtr/mtr0log.c b/storage/innobase/mtr/mtr0log.c index 04eeb4391cd..864970cef40 100644 --- a/storage/innobase/mtr/mtr0log.c +++ b/storage/innobase/mtr/mtr0log.c @@ -408,7 +408,7 @@ mlog_parse_string( ptr += 2; if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE) - || UNIV_UNLIKELY(len + offset) > UNIV_PAGE_SIZE) { + || UNIV_UNLIKELY(len + offset > UNIV_PAGE_SIZE)) { recv_sys->found_corrupt_log = TRUE; return(NULL); diff --git a/storage/innobase/page/page0zip.c b/storage/innobase/page/page0zip.c index 98640a8e6fb..4c5371370da 100644 --- a/storage/innobase/page/page0zip.c +++ b/storage/innobase/page/page0zip.c @@ -4440,7 +4440,7 @@ page_zip_reorganize( log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); #ifndef UNIV_HOTBACKUP - temp_block = buf_block_alloc(buf_pool, 0); + temp_block = buf_block_alloc(buf_pool); btr_search_drop_page_hash_index(block); block->check_index_page_at_flush = TRUE; #else /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/rem/rem0cmp.c b/storage/innobase/rem/rem0cmp.c index 35b67992558..04d2c15437b 100644 --- a/storage/innobase/rem/rem0cmp.c +++ b/storage/innobase/rem/rem0cmp.c @@ -862,6 +862,10 @@ cmp_rec_rec_with_match( const ulint* offsets1,/*!< in: rec_get_offsets(rec1, index) */ const ulint* offsets2,/*!< in: rec_get_offsets(rec2, index) */ dict_index_t* index, /*!< in: data dictionary index */ + ibool nulls_unequal, + /* in: TRUE if this is for index statistics + cardinality estimation, and innodb_stats_method + is "nulls_unequal" or "nulls_ignored" */ ulint* matched_fields, /*!< in/out: number of already completely matched fields; when the function returns, contains the value the for current @@ -961,9 +965,13 @@ cmp_rec_rec_with_match( || rec2_f_len == UNIV_SQL_NULL) { if (rec1_f_len == rec2_f_len) { - - goto next_field; - + /* This is limited to stats collection, + cannot use it for regular search */ + if (nulls_unequal) { + ret = -1; + } else { + goto next_field; + } } else if (rec2_f_len == UNIV_SQL_NULL) { /* We define the SQL null to be the diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index dbfba358f9f..e0414cde80d 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -2122,7 +2122,7 @@ function_exit: err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, big_rec, &mtr); + rec, offsets, &mtr, FALSE, big_rec); if (modify) { dtuple_big_rec_free(big_rec); diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c index 2ab93a2e151..03e37a8c4a4 100644 --- a/storage/innobase/row/row0merge.c +++ b/storage/innobase/row/row0merge.c @@ -2158,13 +2158,15 @@ row_merge_drop_temp_indexes(void) } /*********************************************************************//** -Create a merge file. */ -static -void -row_merge_file_create( -/*==================*/ - merge_file_t* merge_file) /*!< out: merge file structure */ +Creates temperary merge files, and if UNIV_PFS_IO defined, register +the file descriptor with Performance Schema. +@return File descriptor */ +UNIV_INLINE +int +row_merge_file_create_low(void) +/*===========================*/ { + int fd; #ifdef UNIV_PFS_IO /* This temp file open does not go through normal file APIs, add instrumentation to register with @@ -2176,37 +2178,59 @@ row_merge_file_create( "Innodb Merge Temp File", __FILE__, __LINE__); #endif - merge_file->fd = innobase_mysql_tmpfile(); - merge_file->offset = 0; - merge_file->n_rec = 0; + fd = innobase_mysql_tmpfile(); #ifdef UNIV_PFS_IO - register_pfs_file_open_end(locker, merge_file->fd); + register_pfs_file_open_end(locker, fd); #endif + return(fd); } - /*********************************************************************//** -Destroy a merge file. */ +Create a merge file. */ static void -row_merge_file_destroy( -/*===================*/ +row_merge_file_create( +/*==================*/ merge_file_t* merge_file) /*!< out: merge file structure */ { + merge_file->fd = row_merge_file_create_low(); + merge_file->offset = 0; + merge_file->n_rec = 0; +} + +/*********************************************************************//** +Destroy a merge file. And de-register the file from Performance Schema +if UNIV_PFS_IO is defined. */ +UNIV_INLINE +void +row_merge_file_destroy_low( +/*=======================*/ + int fd) /*!< in: merge file descriptor */ +{ #ifdef UNIV_PFS_IO struct PSI_file_locker* locker = NULL; PSI_file_locker_state state; - register_pfs_file_io_begin(&state, locker, merge_file->fd, 0, PSI_FILE_CLOSE, + register_pfs_file_io_begin(&state, locker, + fd, 0, PSI_FILE_CLOSE, __FILE__, __LINE__); #endif - if (merge_file->fd != -1) { - close(merge_file->fd); - merge_file->fd = -1; - } - + close(fd); #ifdef UNIV_PFS_IO register_pfs_file_io_end(locker, 0); #endif } +/*********************************************************************//** +Destroy a merge file. */ +static +void +row_merge_file_destroy( +/*===================*/ + merge_file_t* merge_file) /*!< out: merge file structure */ +{ + if (merge_file->fd != -1) { + row_merge_file_destroy_low(merge_file->fd); + merge_file->fd = -1; + } +} /*********************************************************************//** Determine the precise type of a column that is added to a tem @@ -2600,7 +2624,7 @@ row_merge_build_indexes( row_merge_file_create(&merge_files[i]); } - tmpfd = innobase_mysql_tmpfile(); + tmpfd = row_merge_file_create_low(); /* Reset the MySQL row buffer that is used when reporting duplicate keys. */ @@ -2642,7 +2666,7 @@ row_merge_build_indexes( } func_exit: - close(tmpfd); + row_merge_file_destroy_low(tmpfd); for (i = 0; i < n_indexes; i++) { row_merge_file_destroy(&merge_files[i]); diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 63f30276df6..a7b0cabfa4b 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1939,15 +1939,13 @@ err_exit: err = trx->error_state; - if (UNIV_UNLIKELY(err != DB_SUCCESS)) { + switch (err) { + case DB_SUCCESS: + break; + case DB_OUT_OF_FILE_SPACE: trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, NULL); - /* TO DO: free table? The code below will dereference - table->name, though. */ - } - switch (err) { - case DB_OUT_OF_FILE_SPACE: ut_print_timestamp(stderr); fputs(" InnoDB: Warning: cannot create table ", stderr); @@ -1962,9 +1960,13 @@ err_exit: break; case DB_DUPLICATE_KEY: + default: /* We may also get err == DB_ERROR if the .ibd file for the table already exists */ + trx->error_state = DB_SUCCESS; + trx_general_rollback_for_mysql(trx, NULL); + dict_mem_table_free(table); break; } diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index 08abc8a3e59..83e7c9e4857 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -489,8 +489,11 @@ Purges an update of an existing record. Also purges an update of a delete marked record if that record contained an externally stored field. */ static void -row_purge_upd_exist_or_extern( -/*==========================*/ +row_purge_upd_exist_or_extern_func( +/*===============================*/ +#ifdef UNIV_DEBUG + const que_thr_t*thr, /*!< in: query thread */ +#endif /* UNIV_DEBUG */ purge_node_t* node) /*!< in: row purge node */ { mem_heap_t* heap; @@ -515,8 +518,8 @@ row_purge_upd_exist_or_extern( while (node->index != NULL) { index = node->index; - if (row_upd_changes_ord_field_binary(NULL, NULL, node->index, - node->update)) { + if (row_upd_changes_ord_field_binary(node->index, node->update, + thr, NULL, NULL)) { /* Build the older version of the index entry */ entry = row_build_index_entry(node->row, NULL, index, heap); @@ -598,6 +601,14 @@ skip_secondaries: } } +#ifdef UNIV_DEBUG +# define row_purge_upd_exist_or_extern(thr,node) \ + row_purge_upd_exist_or_extern_func(thr,node) +#else /* UNIV_DEBUG */ +# define row_purge_upd_exist_or_extern(thr,node) \ + row_purge_upd_exist_or_extern_func(node) +#endif /* UNIV_DEBUG */ + /***********************************************************//** Parses the row reference and other info in a modify undo log record. @return TRUE if purge operation required: NOTE that then the CALLER @@ -704,47 +715,32 @@ err_exit: /***********************************************************//** Fetches an undo log record and does the purge for the recorded operation. If none left, or the current purge completed, returns the control to the -parent node, which is always a query thread node. -@return DB_SUCCESS if operation successfully completed, else error code */ -static -ulint +parent node, which is always a query thread node. */ +static __attribute__((nonnull)) +void row_purge( /*======*/ purge_node_t* node, /*!< in: row purge node */ que_thr_t* thr) /*!< in: query thread */ { - roll_ptr_t roll_ptr; - ibool purge_needed; ibool updated_extern; - trx_t* trx; - ut_ad(node && thr); - - trx = thr_get_trx(thr); + ut_ad(node); + ut_ad(thr); - node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr, - &(node->reservation), + node->undo_rec = trx_purge_fetch_next_rec(&node->roll_ptr, + &node->reservation, node->heap); if (!node->undo_rec) { /* Purge completed for this query thread */ thr->run_node = que_node_get_parent(node); - return(DB_SUCCESS); - } - - node->roll_ptr = roll_ptr; - - if (node->undo_rec == &trx_purge_dummy_rec) { - purge_needed = FALSE; - } else { - purge_needed = row_purge_parse_undo_rec(node, &updated_extern, - thr); - /* If purge_needed == TRUE, we must also remember to unfreeze - data dictionary! */ + return; } - if (purge_needed) { + if (node->undo_rec != &trx_purge_dummy_rec + && row_purge_parse_undo_rec(node, &updated_extern, thr)) { node->found_clust = FALSE; node->index = dict_table_get_next_index( @@ -756,14 +752,14 @@ row_purge( } else if (updated_extern || node->rec_type == TRX_UNDO_UPD_EXIST_REC) { - row_purge_upd_exist_or_extern(node); + row_purge_upd_exist_or_extern(thr, node); } if (node->found_clust) { btr_pcur_close(&(node->pcur)); } - row_mysql_unfreeze_data_dictionary(trx); + row_mysql_unfreeze_data_dictionary(thr_get_trx(thr)); } /* Do some cleanup */ @@ -771,8 +767,6 @@ row_purge( mem_heap_empty(node->heap); thr->run_node = node; - - return(DB_SUCCESS); } /***********************************************************//** @@ -786,9 +780,6 @@ row_purge_step( que_thr_t* thr) /*!< in: query thread */ { purge_node_t* node; -#ifdef UNIV_DEBUG - ulint err; -#endif /* UNIV_DEBUG */ ut_ad(thr); @@ -796,12 +787,7 @@ row_purge_step( ut_ad(que_node_get_type(node) == QUE_NODE_PURGE); -#ifdef UNIV_DEBUG - err = -#endif /* UNIV_DEBUG */ row_purge(node, thr); - ut_ad(err == DB_SUCCESS); - return(thr); } diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 0d4c42b958c..2188fdeff49 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -173,40 +173,26 @@ row_undo_mod_remove_clust_low( mtr_t* mtr, /*!< in: mtr */ ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { - btr_pcur_t* pcur; btr_cur_t* btr_cur; ulint err; - ibool success; ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC); - pcur = &(node->pcur); - btr_cur = btr_pcur_get_btr_cur(pcur); - success = btr_pcur_restore_position(mode, pcur, mtr); + /* Find out if the record has been purged already + or if we can remove it. */ - if (!success) { + if (!btr_pcur_restore_position(mode, &node->pcur, mtr) + || row_vers_must_preserve_del_marked(node->new_trx_id, mtr)) { return(DB_SUCCESS); } - /* Find out if we can remove the whole clustered index record */ - - if (node->rec_type == TRX_UNDO_UPD_DEL_REC - && !row_vers_must_preserve_del_marked(node->new_trx_id, mtr)) { - - /* Ok, we can remove */ - } else { - return(DB_SUCCESS); - } + btr_cur = btr_pcur_get_btr_cur(&node->pcur); if (mode == BTR_MODIFY_LEAF) { - success = btr_cur_optimistic_delete(btr_cur, mtr); - - if (success) { - err = DB_SUCCESS; - } else { - err = DB_FAIL; - } + err = btr_cur_optimistic_delete(btr_cur, mtr) + ? DB_SUCCESS + : DB_FAIL; } else { ut_ad(mode == BTR_MODIFY_TREE); @@ -693,8 +679,9 @@ row_undo_mod_upd_exist_sec( while (node->index != NULL) { index = node->index; - if (row_upd_changes_ord_field_binary( - node->row, node->ext, node->index, node->update)) { + if (row_upd_changes_ord_field_binary(node->index, node->update, + thr, + node->row, node->ext)) { /* Build the newest version of the index entry */ entry = row_build_index_entry(node->row, node->ext, diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 03ed40c6647..c6bff0fccd6 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1192,25 +1192,31 @@ NOTE: we compare the fields as binary strings! @return TRUE if update vector changes an ordering field in the index record */ UNIV_INTERN ibool -row_upd_changes_ord_field_binary( -/*=============================*/ +row_upd_changes_ord_field_binary_func( +/*==================================*/ + dict_index_t* index, /*!< in: index of the record */ + const upd_t* update, /*!< in: update vector for the row; NOTE: the + field numbers in this MUST be clustered index + positions! */ +#ifdef UNIV_DEBUG + const que_thr_t*thr, /*!< in: query thread */ +#endif /* UNIV_DEBUG */ const dtuple_t* row, /*!< in: old value of row, or NULL if the row and the data values in update are not known when this function is called, e.g., at compile time */ - const row_ext_t*ext, /*!< NULL, or prefixes of the externally + const row_ext_t*ext) /*!< NULL, or prefixes of the externally stored columns in the old row */ - dict_index_t* index, /*!< in: index of the record */ - const upd_t* update) /*!< in: update vector for the row; NOTE: the - field numbers in this MUST be clustered index - positions! */ { ulint n_unique; ulint i; const dict_index_t* clust_index; - ut_ad(update); ut_ad(index); + ut_ad(update); + ut_ad(thr); + ut_ad(thr->graph); + ut_ad(thr->graph->trx); n_unique = dict_index_get_n_unique(index); @@ -1252,6 +1258,10 @@ row_upd_changes_ord_field_binary( || dfield_is_null(dfield)) { /* do nothing special */ } else if (UNIV_LIKELY_NULL(ext)) { + /* Silence a compiler warning without + silencing a Valgrind error. */ + dfield_len = 0; + UNIV_MEM_INVALID(&dfield_len, sizeof dfield_len); /* See if the column is stored externally. */ buf = row_ext_lookup(ext, col_no, &dfield_len); @@ -1259,9 +1269,14 @@ row_upd_changes_ord_field_binary( if (UNIV_LIKELY_NULL(buf)) { if (UNIV_UNLIKELY(buf == field_ref_zero)) { - /* This should never happen, but - we try to fail safe here. */ - ut_ad(0); + /* The externally stored field + was not written yet. This + record should only be seen by + recv_recovery_rollback_active(), + when the server had crashed before + storing the field. */ + ut_ad(thr->graph->trx->is_recovered); + ut_ad(trx_is_recv(thr->graph->trx)); return(TRUE); } @@ -1636,8 +1651,8 @@ row_upd_sec_step( ut_ad(!dict_index_is_clust(node->index)); if (node->state == UPD_NODE_UPDATE_ALL_SEC - || row_upd_changes_ord_field_binary(node->row, node->ext, - node->index, node->update)) { + || row_upd_changes_ord_field_binary(node->index, node->update, + thr, node->row, node->ext)) { return(row_upd_sec_index_entry(node, thr)); } @@ -1967,7 +1982,7 @@ row_upd_clust_rec( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr); + mtr, TRUE, big_rec); mtr_commit(mtr); } @@ -2165,8 +2180,8 @@ exit_func: row_upd_store_row(node); - if (row_upd_changes_ord_field_binary(node->row, node->ext, index, - node->update)) { + if (row_upd_changes_ord_field_binary(index, node->update, thr, + node->row, node->ext)) { /* Update causes an ordering field (ordering fields within the B-tree) of the clustered index record to change: perform diff --git a/storage/innobase/row/row0vers.c b/storage/innobase/row/row0vers.c index 2e12361312c..91c230db135 100644 --- a/storage/innobase/row/row0vers.c +++ b/storage/innobase/row/row0vers.c @@ -669,11 +669,15 @@ row_vers_build_for_semi_consistent_read( mutex_enter(&kernel_mutex); version_trx = trx_get_on_id(version_trx_id); + if (version_trx + && (version_trx->conc_state == TRX_COMMITTED_IN_MEMORY + || version_trx->conc_state == TRX_NOT_STARTED)) { + + version_trx = NULL; + } mutex_exit(&kernel_mutex); - if (!version_trx - || version_trx->conc_state == TRX_NOT_STARTED - || version_trx->conc_state == TRX_COMMITTED_IN_MEMORY) { + if (!version_trx) { /* We found a version that belongs to a committed transaction: return it. */ diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 1c57d6960d0..826145005a4 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -275,6 +275,11 @@ UNIV_INTERN ulong srv_purge_batch_size = 20; /* variable counts amount of data read in total (in bytes) */ UNIV_INTERN ulint srv_data_read = 0; +/* Internal setting for "innodb_stats_method". Decides how InnoDB treats +NULL value when collecting statistics. By default, it is set to +SRV_STATS_NULLS_EQUAL(0), ie. all NULL value are treated equal */ +ulong srv_innodb_stats_method = SRV_STATS_NULLS_EQUAL; + /* here we count the amount of data written in total (in bytes) */ UNIV_INTERN ulint srv_data_written = 0; diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index acb448a1a67..2a9ad0e7541 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -1327,13 +1327,16 @@ innobase_start_or_create_for_mysql(void) ut_a(srv_n_file_io_threads <= SRV_MAX_N_IO_THREADS); - /* TODO: Investigate if SRV_N_PENDING_IOS_PER_THREAD (32) limit - still applies to windows. */ - if (!srv_use_native_aio) { - io_limit = 8 * SRV_N_PENDING_IOS_PER_THREAD; - } else { + io_limit = 8 * SRV_N_PENDING_IOS_PER_THREAD; + + /* On Windows when using native aio the number of aio requests + that a thread can handle at a given time is limited to 32 + i.e.: SRV_N_PENDING_IOS_PER_THREAD */ +# ifdef __WIN__ + if (srv_use_native_aio) { io_limit = SRV_N_PENDING_IOS_PER_THREAD; } +# endif /* __WIN__ */ os_aio_init(io_limit, srv_n_read_io_threads, diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index ce9d42c4921..3ecbce72ebd 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -714,7 +714,7 @@ print: fprintf(stderr, "rw-lock %p ", (void*) lock); sync_array_cell_print(stderr, cell); - rw_lock_debug_print(debug); + rw_lock_debug_print(stderr, debug); return(TRUE); } } diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 783cff3bf82..295a010f9d7 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -936,7 +936,7 @@ rw_lock_list_print_info( info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { - rw_lock_debug_print(info); + rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } } @@ -984,7 +984,7 @@ rw_lock_print( info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { - rw_lock_debug_print(info); + rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } } @@ -996,28 +996,29 @@ UNIV_INTERN void rw_lock_debug_print( /*================*/ + FILE* f, /*!< in: output stream */ rw_lock_debug_t* info) /*!< in: debug struct */ { ulint rwt; rwt = info->lock_type; - fprintf(stderr, "Locked: thread %lu file %s line %lu ", + fprintf(f, "Locked: thread %lu file %s line %lu ", (ulong) os_thread_pf(info->thread_id), info->file_name, (ulong) info->line); if (rwt == RW_LOCK_SHARED) { - fputs("S-LOCK", stderr); + fputs("S-LOCK", f); } else if (rwt == RW_LOCK_EX) { - fputs("X-LOCK", stderr); + fputs("X-LOCK", f); } else if (rwt == RW_LOCK_WAIT_EX) { - fputs("WAIT X-LOCK", stderr); + fputs("WAIT X-LOCK", f); } else { ut_error; } if (info->pass != 0) { - fprintf(stderr, " pass value %lu", (ulong) info->pass); + fprintf(f, " pass value %lu", (ulong) info->pass); } - putc('\n', stderr); + putc('\n', f); } /***************************************************************//** diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 761cc4c805e..453314f465d 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -222,21 +222,40 @@ UNIV_INTERN mysql_pfs_key_t mutex_list_mutex_key; UNIV_INTERN ibool sync_order_checks_on = FALSE; #endif /* UNIV_SYNC_DEBUG */ +/** Number of slots reserved for each OS thread in the sync level array */ +static const ulint SYNC_THREAD_N_LEVELS = 10000; + +typedef struct sync_arr_struct sync_arr_t; + +/** Array for tracking sync levels per thread. */ +struct sync_arr_struct { + ulint in_use; /*!< Number of active cells */ + ulint n_elems; /*!< Number of elements in the array */ + ulint max_elems; /*!< Maximum elements */ + ulint next_free; /*!< ULINT_UNDEFINED or index of next + free slot */ + sync_level_t* elems; /*!< Array elements */ +}; + /** Mutexes or rw-locks held by a thread */ struct sync_thread_struct{ - os_thread_id_t id; /*!< OS thread id */ - sync_level_t* levels; /*!< level array for this thread; if - this is NULL this slot is unused */ + os_thread_id_t id; /*!< OS thread id */ + sync_arr_t* levels; /*!< level array for this thread; if + this is NULL this slot is unused */ }; -/** Number of slots reserved for each OS thread in the sync level array */ -#define SYNC_THREAD_N_LEVELS 10000 - /** An acquired mutex or rw-lock and its level in the latching order */ struct sync_level_struct{ - void* latch; /*!< pointer to a mutex or an rw-lock; NULL means that - the slot is empty */ - ulint level; /*!< level of the latch in the latching order */ + void* latch; /*!< pointer to a mutex or an + rw-lock; NULL means that + the slot is empty */ + ulint level; /*!< level of the latch in the + latching order. This field is + overloaded to serve as a node in a + linked list of free nodes too. When + latch == NULL then this will contain + the ordinal value of the next free + element */ }; /******************************************************************//** @@ -745,27 +764,28 @@ mutex_n_reserved(void) /*==================*/ { mutex_t* mutex; - ulint count = 0; + ulint count = 0; mutex_enter(&mutex_list_mutex); - mutex = UT_LIST_GET_FIRST(mutex_list); + for (mutex = UT_LIST_GET_FIRST(mutex_list); + mutex != NULL; + mutex = UT_LIST_GET_NEXT(list, mutex)) { - while (mutex != NULL) { if (mutex_get_lock_word(mutex) != 0) { count++; } - - mutex = UT_LIST_GET_NEXT(list, mutex); } mutex_exit(&mutex_list_mutex); ut_a(count >= 1); - return(count - 1); /* Subtract one, because this function itself - was holding one mutex (mutex_list_mutex) */ + /* Subtract one, because this function itself was holding + one mutex (mutex_list_mutex) */ + + return(count - 1); } /******************************************************************//** @@ -781,20 +801,6 @@ sync_all_freed(void) } /******************************************************************//** -Gets the value in the nth slot in the thread level arrays. -@return pointer to thread slot */ -static -sync_thread_t* -sync_thread_level_arrays_get_nth( -/*=============================*/ - ulint n) /*!< in: slot number */ -{ - ut_ad(n < OS_THREAD_MAX_N); - - return(sync_thread_level_arrays + n); -} - -/******************************************************************//** Looks for the thread slot for the calling thread. @return pointer to thread slot, NULL if not found */ static @@ -803,15 +809,15 @@ sync_thread_level_arrays_find_slot(void) /*====================================*/ { - sync_thread_t* slot; - os_thread_id_t id; ulint i; + os_thread_id_t id; id = os_thread_get_curr_id(); for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_t* slot; - slot = sync_thread_level_arrays_get_nth(i); + slot = &sync_thread_level_arrays[i]; if (slot->levels && os_thread_eq(slot->id, id)) { @@ -831,12 +837,12 @@ sync_thread_level_arrays_find_free(void) /*====================================*/ { - sync_thread_t* slot; ulint i; for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_t* slot; - slot = sync_thread_level_arrays_get_nth(i); + slot = &sync_thread_level_arrays[i]; if (slot->levels == NULL) { @@ -848,19 +854,44 @@ sync_thread_level_arrays_find_free(void) } /******************************************************************//** -Gets the value in the nth slot in the thread level array. -@return pointer to level slot */ +Print warning. */ static -sync_level_t* -sync_thread_levels_get_nth( -/*=======================*/ - sync_level_t* arr, /*!< in: pointer to level array for an OS - thread */ - ulint n) /*!< in: slot number */ +void +sync_print_warning( +/*===============*/ + const sync_level_t* slot) /*!< in: slot for which to + print warning */ { - ut_ad(n < SYNC_THREAD_N_LEVELS); + mutex_t* mutex; + + mutex = slot->latch; + + if (mutex->magic_n == MUTEX_MAGIC_N) { + fprintf(stderr, + "Mutex created at %s %lu\n", + mutex->cfile_name, (ulong) mutex->cline); + + if (mutex_get_lock_word(mutex) != 0) { + ulint line; + const char* file_name; + os_thread_id_t thread_id; + + mutex_get_debug_info( + mutex, &file_name, &line, &thread_id); + + fprintf(stderr, + "InnoDB: Locked mutex:" + " addr %p thread %ld file %s line %ld\n", + (void*) mutex, os_thread_pf(thread_id), + file_name, (ulong) line); + } else { + fputs("Not locked\n", stderr); + } + } else { + rw_lock_t* lock = slot->latch; - return(arr + n); + rw_lock_print(lock); + } } /******************************************************************//** @@ -871,69 +902,29 @@ static ibool sync_thread_levels_g( /*=================*/ - sync_level_t* arr, /*!< in: pointer to level array for an OS + sync_arr_t* arr, /*!< in: pointer to level array for an OS thread */ ulint limit, /*!< in: level limit */ ulint warn) /*!< in: TRUE=display a diagnostic message */ { - sync_level_t* slot; - rw_lock_t* lock; - mutex_t* mutex; ulint i; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { - - slot = sync_thread_levels_get_nth(arr, i); - - if (slot->latch != NULL) { - if (slot->level <= limit) { - - if (!warn) { - - return(FALSE); - } + for (i = 0; i < arr->n_elems; i++) { + const sync_level_t* slot; - lock = slot->latch; - mutex = slot->latch; + slot = &arr->elems[i]; + if (slot->latch != NULL && slot->level <= limit) { + if (warn) { fprintf(stderr, "InnoDB: sync levels should be" " > %lu but a level is %lu\n", (ulong) limit, (ulong) slot->level); - if (mutex->magic_n == MUTEX_MAGIC_N) { - fprintf(stderr, - "Mutex created at %s %lu\n", - mutex->cfile_name, - (ulong) mutex->cline); - - if (mutex_get_lock_word(mutex) != 0) { - const char* file_name; - ulint line; - os_thread_id_t thread_id; - - mutex_get_debug_info( - mutex, &file_name, - &line, &thread_id); - - fprintf(stderr, - "InnoDB: Locked mutex:" - " addr %p thread %ld" - " file %s line %ld\n", - (void*) mutex, - os_thread_pf( - thread_id), - file_name, - (ulong) line); - } else { - fputs("Not locked\n", stderr); - } - } else { - rw_lock_print(lock); - } - - return(FALSE); + sync_print_warning(slot); } + + return(FALSE); } } @@ -942,31 +933,29 @@ sync_thread_levels_g( /******************************************************************//** Checks if the level value is stored in the level array. -@return TRUE if stored */ +@return slot if found or NULL */ static -ibool +const sync_level_t* sync_thread_levels_contain( /*=======================*/ - sync_level_t* arr, /*!< in: pointer to level array for an OS + sync_arr_t* arr, /*!< in: pointer to level array for an OS thread */ ulint level) /*!< in: level */ { - sync_level_t* slot; ulint i; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < arr->n_elems; i++) { + const sync_level_t* slot; - slot = sync_thread_levels_get_nth(arr, i); + slot = &arr->elems[i]; - if (slot->latch != NULL) { - if (slot->level == level) { + if (slot->latch != NULL && slot->level == level) { - return(TRUE); - } + return(slot); } } - return(FALSE); + return(NULL); } /******************************************************************//** @@ -980,10 +969,9 @@ sync_thread_levels_contains( ulint level) /*!< in: latching order level (SYNC_DICT, ...)*/ { - sync_level_t* arr; - sync_thread_t* thread_slot; - sync_level_t* slot; ulint i; + sync_arr_t* arr; + sync_thread_t* thread_slot; if (!sync_order_checks_on) { @@ -1003,9 +991,10 @@ sync_thread_levels_contains( arr = thread_slot->levels; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < arr->n_elems; i++) { + sync_level_t* slot; - slot = sync_thread_levels_get_nth(arr, i); + slot = &arr->elems[i]; if (slot->latch != NULL && slot->level == level) { @@ -1031,10 +1020,9 @@ sync_thread_levels_nonempty_gen( also purge_is_running mutex is allowed */ { - sync_level_t* arr; - sync_thread_t* thread_slot; - sync_level_t* slot; ulint i; + sync_arr_t* arr; + sync_thread_t* thread_slot; if (!sync_order_checks_on) { @@ -1054,9 +1042,10 @@ sync_thread_levels_nonempty_gen( arr = thread_slot->levels; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < arr->n_elems; ++i) { + const sync_level_t* slot; - slot = sync_thread_levels_get_nth(arr, i); + slot = &arr->elems[i]; if (slot->latch != NULL && (!dict_mutex_allowed @@ -1098,10 +1087,10 @@ sync_thread_add_level( ulint level) /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ { - sync_level_t* array; + ulint i; sync_level_t* slot; + sync_arr_t* array; sync_thread_t* thread_slot; - ulint i; if (!sync_order_checks_on) { @@ -1126,20 +1115,23 @@ sync_thread_add_level( thread_slot = sync_thread_level_arrays_find_slot(); if (thread_slot == NULL) { - /* We have to allocate the level array for a new thread */ - array = ut_malloc(sizeof(sync_level_t) * SYNC_THREAD_N_LEVELS); + ulint sz; - thread_slot = sync_thread_level_arrays_find_free(); + sz = sizeof(*array) + + (sizeof(*array->elems) * SYNC_THREAD_N_LEVELS); - thread_slot->id = os_thread_get_curr_id(); - thread_slot->levels = array; + /* We have to allocate the level array for a new thread */ + array = calloc(sz, sizeof(char)); + ut_a(array != NULL); - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + array->next_free = ULINT_UNDEFINED; + array->max_elems = SYNC_THREAD_N_LEVELS; + array->elems = (sync_level_t*) &array[1]; - slot = sync_thread_levels_get_nth(array, i); + thread_slot = sync_thread_level_arrays_find_free(); - slot->latch = NULL; - } + thread_slot->levels = array; + thread_slot->id = os_thread_get_curr_id(); } array = thread_slot->levels; @@ -1303,19 +1295,26 @@ sync_thread_add_level( ut_error; } - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + if (array->next_free == ULINT_UNDEFINED) { + ut_a(array->n_elems < array->max_elems); - slot = sync_thread_levels_get_nth(array, i); + i = array->n_elems++; + } else { + i = array->next_free; + array->next_free = array->elems[i].level; + } - if (slot->latch == NULL) { - slot->latch = latch; - slot->level = level; + ut_a(i < array->n_elems); + ut_a(i != ULINT_UNDEFINED); - break; - } - } + ++array->in_use; + + slot = &array->elems[i]; - ut_a(i < SYNC_THREAD_N_LEVELS); + ut_a(slot->latch == NULL); + + slot->latch = latch; + slot->level = level; mutex_exit(&sync_thread_mutex); } @@ -1331,8 +1330,7 @@ sync_thread_reset_level( /*====================*/ void* latch) /*!< in: pointer to a mutex or an rw-lock */ { - sync_level_t* array; - sync_level_t* slot; + sync_arr_t* array; sync_thread_t* thread_slot; ulint i; @@ -1363,17 +1361,37 @@ sync_thread_reset_level( array = thread_slot->levels; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < array->n_elems; i++) { + sync_level_t* slot; - slot = sync_thread_levels_get_nth(array, i); + slot = &array->elems[i]; - if (slot->latch == latch) { - slot->latch = NULL; + if (slot->latch != latch) { + continue; + } - mutex_exit(&sync_thread_mutex); + slot->latch = NULL; - return(TRUE); + /* Update the free slot list. See comment in sync_level_t + for the level field. */ + slot->level = array->next_free; + array->next_free = i; + + ut_a(array->in_use >= 1); + --array->in_use; + + /* If all cells are idle then reset the free + list. The assumption is that this will save + time when we need to scan up to n_elems. */ + + if (array->in_use == 0) { + array->n_elems = 0; + array->next_free = ULINT_UNDEFINED; } + + mutex_exit(&sync_thread_mutex); + + return(TRUE); } if (((mutex_t*) latch)->magic_n != MUTEX_MAGIC_N) { @@ -1403,11 +1421,6 @@ void sync_init(void) /*===========*/ { -#ifdef UNIV_SYNC_DEBUG - sync_thread_t* thread_slot; - ulint i; -#endif /* UNIV_SYNC_DEBUG */ - ut_a(sync_initialized == FALSE); sync_initialized = TRUE; @@ -1421,13 +1434,10 @@ sync_init(void) /* Create the thread latch level array where the latch levels are stored for each OS thread */ - sync_thread_level_arrays = ut_malloc(OS_THREAD_MAX_N - * sizeof(sync_thread_t)); - for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_level_arrays = calloc( + sizeof(sync_thread_t), OS_THREAD_MAX_N); + ut_a(sync_thread_level_arrays != NULL); - thread_slot = sync_thread_level_arrays_get_nth(i); - thread_slot->levels = NULL; - } #endif /* UNIV_SYNC_DEBUG */ /* Init the mutex list and create the mutex to protect it. */ @@ -1454,6 +1464,34 @@ sync_init(void) #endif /* UNIV_SYNC_DEBUG */ } +#ifdef UNIV_SYNC_DEBUG +/******************************************************************//** +Frees all debug memory. */ +static +void +sync_thread_level_arrays_free(void) +/*===============================*/ + +{ + ulint i; + + for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_t* slot; + + slot = &sync_thread_level_arrays[i]; + + /* If this slot was allocated then free the slot memory too. */ + if (slot->levels != NULL) { + free(slot->levels); + slot->levels = NULL; + } + } + + free(sync_thread_level_arrays); + sync_thread_level_arrays = NULL; +} +#endif /* UNIV_SYNC_DEBUG */ + /******************************************************************//** Frees the resources in InnoDB's own synchronization data structures. Use os_sync_free() after calling this. */ @@ -1466,17 +1504,20 @@ sync_close(void) sync_array_free(sync_primary_wait_array); - mutex = UT_LIST_GET_FIRST(mutex_list); + for (mutex = UT_LIST_GET_FIRST(mutex_list); + mutex != NULL; + /* No op */) { - while (mutex) { #ifdef UNIV_MEM_DEBUG if (mutex == &mem_hash_mutex) { mutex = UT_LIST_GET_NEXT(list, mutex); continue; } #endif /* UNIV_MEM_DEBUG */ + mutex_free(mutex); - mutex = UT_LIST_GET_FIRST(mutex_list); + + mutex = UT_LIST_GET_FIRST(mutex_list); } mutex_free(&mutex_list_mutex); @@ -1485,6 +1526,8 @@ sync_close(void) /* Switch latching order checks on in sync0sync.c */ sync_order_checks_on = FALSE; + + sync_thread_level_arrays_free(); #endif /* UNIV_SYNC_DEBUG */ sync_initialized = FALSE; diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c index 876a00fb935..f9d421e3705 100644 --- a/storage/innobase/trx/trx0roll.c +++ b/storage/innobase/trx/trx0roll.c @@ -47,8 +47,8 @@ Created 3/26/1996 Heikki Tuuri rollback */ #define TRX_ROLL_TRUNC_THRESHOLD 1 -/** In crash recovery, the current trx to be rolled back */ -static trx_t* trx_roll_crash_recv_trx = NULL; +/** In crash recovery, the current trx to be rolled back; NULL otherwise */ +static const trx_t* trx_roll_crash_recv_trx = NULL; /** In crash recovery we set this to the undo n:o of the current trx to be rolled back. Then we can print how many % the rollback has progressed. */ diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 7f2ca1f1471..4bbcee210b0 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -2004,18 +2004,18 @@ trx_recover_for_mysql( /*******************************************************************//** This function is used to find one X/Open XA distributed transaction which is in the prepared state -@return trx or NULL */ +@return trx or NULL; on match, the trx->xid will be invalidated */ UNIV_INTERN trx_t* trx_get_trx_by_xid( /*===============*/ - XID* xid) /*!< in: X/Open XA transaction identification */ + const XID* xid) /*!< in: X/Open XA transaction identifier */ { trx_t* trx; if (xid == NULL) { - return (NULL); + return(NULL); } mutex_enter(&kernel_mutex); @@ -2028,10 +2028,16 @@ trx_get_trx_by_xid( of gtrid_length+bqual_length bytes should be the same */ - if (xid->gtrid_length == trx->xid.gtrid_length + if (trx->conc_state == TRX_PREPARED + && xid->gtrid_length == trx->xid.gtrid_length && xid->bqual_length == trx->xid.bqual_length && memcmp(xid->data, trx->xid.data, xid->gtrid_length + xid->bqual_length) == 0) { + + /* Invalidate the XID, so that subsequent calls + will not find it. */ + memset(&trx->xid, 0, sizeof(trx->xid)); + trx->xid.formatID = -1; break; } @@ -2040,14 +2046,5 @@ trx_get_trx_by_xid( mutex_exit(&kernel_mutex); - if (trx) { - if (trx->conc_state != TRX_PREPARED) { - - return(NULL); - } - - return(trx); - } else { - return(NULL); - } + return(trx); } |