diff options
28 files changed, 633 insertions, 92 deletions
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 8fb5ae4a577..73a9791d593 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -383,7 +383,7 @@ static int run_command(char* cmd, if (opt_verbose >= 4) puts(cmd); - if (!(res_file= popen(cmd, "r"))) + if (!(res_file= my_popen(cmd, IF_WIN("rt","r")))) die("popen(\"%s\", \"r\") failed", cmd); while (fgets(buf, sizeof(buf), res_file)) @@ -401,7 +401,7 @@ static int run_command(char* cmd, } } - error= pclose(res_file); + error= my_pclose(res_file); return WEXITSTATUS(error); } diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 59cf7065a69..2e3f0aa79fa 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -871,14 +871,6 @@ static char *my_fgets(char * s, int n, FILE * stream, int *len) return buf; } -/* - Wrapper for popen(). -*/ -static FILE* my_popen(const char *cmd, const char *mode) -{ - return popen(cmd, mode); -} - #ifdef EMBEDDED_LIBRARY #define EMB_SEND_QUERY 1 @@ -1853,7 +1845,7 @@ static int run_command(char* cmd, } } - error= pclose(res_file); + error= my_pclose(res_file); DBUG_RETURN(WEXITSTATUS(error)); } @@ -3439,7 +3431,7 @@ void do_exec(struct st_command *command) { replace_dynstr_append_mem(ds_result, buf, len); } - error= pclose(res_file); + error= my_pclose(res_file); if (display_result_sorted) { @@ -4669,7 +4661,7 @@ void do_perl(struct st_command *command) replace_dynstr_append_mem(&ds_res, buf, len); } } - error= pclose(res_file); + error= my_pclose(res_file); /* Remove the temporary file, but keep it if perl failed */ if (!error) diff --git a/extra/perror.c b/extra/perror.c index 15c12f10353..2daddb6636f 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -200,19 +200,22 @@ int get_ER_error_msg(uint code, const char **name_ptr, const char **msg_ptr) return 0; } -#if defined(__WIN__) +#if defined(_WIN32) static my_bool print_win_error_msg(DWORD error, my_bool verbose) { - LPTSTR s; - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + char *s; + if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, (LPTSTR)&s, 0, + NULL, error, 0, (char *)&s, 0, NULL)) { + char* end = s + strlen(s) - 1; + while (end > s && (*end == '\r' || *end == '\n')) + *end-- = 0; if (verbose) - printf("Win32 error code %lu: %s", error, s); + printf("Win32 error code %lu: %s\n", error, s); else - puts(s); + printf("%s\n",s); LocalFree(s); return 0; } @@ -260,7 +263,7 @@ int main(int argc,char *argv[]) const char *msg; const char *name; char *unknown_error = 0; -#if defined(__WIN__) +#if defined(_WIN32) my_bool skip_win_message= 0; #endif MY_INIT(argv[0]); @@ -351,17 +354,17 @@ int main(int argc,char *argv[]) } if (!found) { -#if defined(__WIN__) +#if defined(_WIN32) if (!(skip_win_message= !print_win_error_msg((DWORD)code, verbose))) { #endif fprintf(stderr,"Illegal error code: %d\n",code); error=1; -#if defined(__WIN__) +#if defined(_WIN32) } #endif } -#if defined(__WIN__) +#if defined(_WIN32) if (!skip_win_message) print_win_error_msg((DWORD)code, verbose); #endif diff --git a/include/my_sys.h b/include/my_sys.h index 4d0eab83da5..f20bbc700b3 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -995,6 +995,16 @@ void *my_mmap(void *, size_t, int, int, int, my_off_t); int my_munmap(void *, size_t); #endif +#ifdef _WIN32 +extern FILE* my_win_popen(const char*, const char*); +extern int my_win_pclose(FILE*); +#define my_popen(A,B) my_win_popen(A,B) +#define my_pclose(A) my_win_pclose(A) +#else +#define my_popen(A,B) popen(A,B) +#define my_pclose(A) pclose(A) +#endif + /* my_getpagesize */ #ifdef HAVE_GETPAGESIZE #define my_getpagesize() getpagesize() diff --git a/mysql-test/include/partition_mrr.inc b/mysql-test/include/partition_mrr.inc new file mode 100644 index 00000000000..4c285791ec7 --- /dev/null +++ b/mysql-test/include/partition_mrr.inc @@ -0,0 +1,46 @@ +--source include/have_partition.inc + +--disable_warnings +drop table if exists t1,t3; +--enable_warnings + +--echo # +--echo # MDEV-20611: MRR scan over partitioned InnoDB table produces "Out of memory" error +--echo # +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +set @tmp=@@storage_engine; +eval set storage_engine=$engine_type; + +create table t3 ( + ID bigint(20) NOT NULL AUTO_INCREMENT, + part_id int, + key_col int, + col2 int, + key(key_col), + PRIMARY KEY (ID,part_id) +) PARTITION BY RANGE (part_id) +(PARTITION p1 VALUES LESS THAN (3), + PARTITION p2 VALUES LESS THAN (7), + PARTITION p3 VALUES LESS THAN (10) +); + +show create table t3; +set storage_engine= @tmp; + +insert into t3 select + A.a+10*B.a, + A.a, + B.a, + 123456 +from t1 A, t1 B; + +set optimizer_switch='mrr=on'; +--replace_column 9 # +explain +select * from t3 force index (key_col) where key_col < 3; +select * from t3 force index (key_col) where key_col < 3; + +drop table t1,t3; + diff --git a/mysql-test/main/partition_mrr_aria.result b/mysql-test/main/partition_mrr_aria.result new file mode 100644 index 00000000000..7a0c35a309e --- /dev/null +++ b/mysql-test/main/partition_mrr_aria.result @@ -0,0 +1,79 @@ +drop table if exists t1,t3; +# +# MDEV-20611: MRR scan over partitioned InnoDB table produces "Out of memory" error +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +set @tmp=@@storage_engine; +set storage_engine=Aria; +create table t3 ( +ID bigint(20) NOT NULL AUTO_INCREMENT, +part_id int, +key_col int, +col2 int, +key(key_col), +PRIMARY KEY (ID,part_id) +) PARTITION BY RANGE (part_id) +(PARTITION p1 VALUES LESS THAN (3), +PARTITION p2 VALUES LESS THAN (7), +PARTITION p3 VALUES LESS THAN (10) +); +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `part_id` int(11) NOT NULL, + `key_col` int(11) DEFAULT NULL, + `col2` int(11) DEFAULT NULL, + PRIMARY KEY (`ID`,`part_id`), + KEY `key_col` (`key_col`) +) ENGINE=Aria DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`part_id`) +(PARTITION `p1` VALUES LESS THAN (3) ENGINE = Aria, + PARTITION `p2` VALUES LESS THAN (7) ENGINE = Aria, + PARTITION `p3` VALUES LESS THAN (10) ENGINE = Aria) +set storage_engine= @tmp; +insert into t3 select +A.a+10*B.a, +A.a, +B.a, +123456 +from t1 A, t1 B; +set optimizer_switch='mrr=on'; +explain +select * from t3 force index (key_col) where key_col < 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range key_col key_col 5 NULL # Using where; Rowid-ordered scan +select * from t3 force index (key_col) where key_col < 3; +ID part_id key_col col2 +1 0 0 123456 +1 1 0 123456 +2 2 0 123456 +10 0 1 123456 +11 1 1 123456 +12 2 1 123456 +20 0 2 123456 +21 1 2 123456 +22 2 2 123456 +3 3 0 123456 +4 4 0 123456 +5 5 0 123456 +6 6 0 123456 +13 3 1 123456 +14 4 1 123456 +15 5 1 123456 +16 6 1 123456 +23 3 2 123456 +24 4 2 123456 +25 5 2 123456 +26 6 2 123456 +7 7 0 123456 +8 8 0 123456 +9 9 0 123456 +17 7 1 123456 +18 8 1 123456 +19 9 1 123456 +27 7 2 123456 +28 8 2 123456 +29 9 2 123456 +drop table t1,t3; diff --git a/mysql-test/main/partition_mrr_aria.test b/mysql-test/main/partition_mrr_aria.test new file mode 100644 index 00000000000..e3dfe8cd9b5 --- /dev/null +++ b/mysql-test/main/partition_mrr_aria.test @@ -0,0 +1,2 @@ +let $engine_type= Aria; +--source include/partition_mrr.inc diff --git a/mysql-test/main/partition_mrr_innodb.result b/mysql-test/main/partition_mrr_innodb.result new file mode 100644 index 00000000000..c188f7e9929 --- /dev/null +++ b/mysql-test/main/partition_mrr_innodb.result @@ -0,0 +1,79 @@ +drop table if exists t1,t3; +# +# MDEV-20611: MRR scan over partitioned InnoDB table produces "Out of memory" error +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +set @tmp=@@storage_engine; +set storage_engine=InnoDB; +create table t3 ( +ID bigint(20) NOT NULL AUTO_INCREMENT, +part_id int, +key_col int, +col2 int, +key(key_col), +PRIMARY KEY (ID,part_id) +) PARTITION BY RANGE (part_id) +(PARTITION p1 VALUES LESS THAN (3), +PARTITION p2 VALUES LESS THAN (7), +PARTITION p3 VALUES LESS THAN (10) +); +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `part_id` int(11) NOT NULL, + `key_col` int(11) DEFAULT NULL, + `col2` int(11) DEFAULT NULL, + PRIMARY KEY (`ID`,`part_id`), + KEY `key_col` (`key_col`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`part_id`) +(PARTITION `p1` VALUES LESS THAN (3) ENGINE = InnoDB, + PARTITION `p2` VALUES LESS THAN (7) ENGINE = InnoDB, + PARTITION `p3` VALUES LESS THAN (10) ENGINE = InnoDB) +set storage_engine= @tmp; +insert into t3 select +A.a+10*B.a, +A.a, +B.a, +123456 +from t1 A, t1 B; +set optimizer_switch='mrr=on'; +explain +select * from t3 force index (key_col) where key_col < 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range key_col key_col 5 NULL # Using where; Rowid-ordered scan +select * from t3 force index (key_col) where key_col < 3; +ID part_id key_col col2 +1 0 0 123456 +1 1 0 123456 +2 2 0 123456 +10 0 1 123456 +11 1 1 123456 +12 2 1 123456 +20 0 2 123456 +21 1 2 123456 +22 2 2 123456 +3 3 0 123456 +4 4 0 123456 +5 5 0 123456 +6 6 0 123456 +13 3 1 123456 +14 4 1 123456 +15 5 1 123456 +16 6 1 123456 +23 3 2 123456 +24 4 2 123456 +25 5 2 123456 +26 6 2 123456 +7 7 0 123456 +8 8 0 123456 +9 9 0 123456 +17 7 1 123456 +18 8 1 123456 +19 9 1 123456 +27 7 2 123456 +28 8 2 123456 +29 9 2 123456 +drop table t1,t3; diff --git a/mysql-test/main/partition_mrr_innodb.test b/mysql-test/main/partition_mrr_innodb.test new file mode 100644 index 00000000000..1eccf070e5c --- /dev/null +++ b/mysql-test/main/partition_mrr_innodb.test @@ -0,0 +1,4 @@ +--source include/have_innodb.inc +let $engine_type= InnoDB; + +--source include/partition_mrr.inc diff --git a/mysql-test/main/partition_mrr_myisam.result b/mysql-test/main/partition_mrr_myisam.result new file mode 100644 index 00000000000..1f1cea8e9d6 --- /dev/null +++ b/mysql-test/main/partition_mrr_myisam.result @@ -0,0 +1,79 @@ +drop table if exists t1,t3; +# +# MDEV-20611: MRR scan over partitioned InnoDB table produces "Out of memory" error +# +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +set @tmp=@@storage_engine; +set storage_engine=myisam; +create table t3 ( +ID bigint(20) NOT NULL AUTO_INCREMENT, +part_id int, +key_col int, +col2 int, +key(key_col), +PRIMARY KEY (ID,part_id) +) PARTITION BY RANGE (part_id) +(PARTITION p1 VALUES LESS THAN (3), +PARTITION p2 VALUES LESS THAN (7), +PARTITION p3 VALUES LESS THAN (10) +); +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT, + `part_id` int(11) NOT NULL, + `key_col` int(11) DEFAULT NULL, + `col2` int(11) DEFAULT NULL, + PRIMARY KEY (`ID`,`part_id`), + KEY `key_col` (`key_col`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`part_id`) +(PARTITION `p1` VALUES LESS THAN (3) ENGINE = MyISAM, + PARTITION `p2` VALUES LESS THAN (7) ENGINE = MyISAM, + PARTITION `p3` VALUES LESS THAN (10) ENGINE = MyISAM) +set storage_engine= @tmp; +insert into t3 select +A.a+10*B.a, +A.a, +B.a, +123456 +from t1 A, t1 B; +set optimizer_switch='mrr=on'; +explain +select * from t3 force index (key_col) where key_col < 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range key_col key_col 5 NULL # Using where; Rowid-ordered scan +select * from t3 force index (key_col) where key_col < 3; +ID part_id key_col col2 +1 0 0 123456 +1 1 0 123456 +2 2 0 123456 +10 0 1 123456 +11 1 1 123456 +12 2 1 123456 +20 0 2 123456 +21 1 2 123456 +22 2 2 123456 +3 3 0 123456 +4 4 0 123456 +5 5 0 123456 +6 6 0 123456 +13 3 1 123456 +14 4 1 123456 +15 5 1 123456 +16 6 1 123456 +23 3 2 123456 +24 4 2 123456 +25 5 2 123456 +26 6 2 123456 +7 7 0 123456 +8 8 0 123456 +9 9 0 123456 +17 7 1 123456 +18 8 1 123456 +19 9 1 123456 +27 7 2 123456 +28 8 2 123456 +29 9 2 123456 +drop table t1,t3; diff --git a/mysql-test/main/partition_mrr_myisam.test b/mysql-test/main/partition_mrr_myisam.test new file mode 100644 index 00000000000..d67a37ab3d2 --- /dev/null +++ b/mysql-test/main/partition_mrr_myisam.test @@ -0,0 +1,3 @@ +let $engine_type= myisam; + +--source include/partition_mrr.inc diff --git a/mysql-test/suite/innodb/r/ibuf_not_empty.result b/mysql-test/suite/innodb/r/ibuf_not_empty.result index dc852dfb8e5..3382c74174e 100644 --- a/mysql-test/suite/innodb/r/ibuf_not_empty.result +++ b/mysql-test/suite/innodb/r/ibuf_not_empty.result @@ -1,3 +1,4 @@ +SET GLOBAL innodb_purge_rseg_truncate_frequency=1; CREATE TABLE t1( a INT AUTO_INCREMENT PRIMARY KEY, b CHAR(1), @@ -5,6 +6,7 @@ c INT, INDEX(b)) ENGINE=InnoDB STATS_PERSISTENT=0; SET GLOBAL innodb_change_buffering_debug = 1; +BEGIN; INSERT INTO t1 VALUES(0,'x',1); INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; @@ -18,14 +20,14 @@ INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; +COMMIT; +InnoDB 0 transactions not purged # restart: --innodb-force-recovery=6 --innodb-change-buffer-dump check table t1; Table Op Msg_type Msg_text test.t1 check Warning InnoDB: Index 'b' contains #### entries, should be 4096. test.t1 check error Corrupt # restart -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; -InnoDB 0 transactions not purged SET GLOBAL innodb_fast_shutdown=0; # restart DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.test b/mysql-test/suite/innodb/t/ibuf_not_empty.test index 14d8728cdf8..a3f4ad9ac5c 100644 --- a/mysql-test/suite/innodb/t/ibuf_not_empty.test +++ b/mysql-test/suite/innodb/t/ibuf_not_empty.test @@ -6,6 +6,7 @@ # The test is not big enough to use change buffering with larger page size. --source include/have_innodb_max_16k.inc +SET GLOBAL innodb_purge_rseg_truncate_frequency=1; --disable_query_log call mtr.add_suppression("InnoDB: Failed to find tablespace for table `test`\\.`t1` in the cache\\. Attempting to load the tablespace with space id"); call mtr.add_suppression("InnoDB: Allocated tablespace ID \\d+ for test.t1, old maximum was"); @@ -29,6 +30,7 @@ SET GLOBAL innodb_change_buffering_debug = 1; # Create enough rows for the table, so that the change buffer will be # used for modifying the secondary index page. There must be multiple # index pages, because changes to the root page are never buffered. +BEGIN; INSERT INTO t1 VALUES(0,'x',1); INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; @@ -42,9 +44,13 @@ INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; +COMMIT; let MYSQLD_DATADIR=`select @@datadir`; let PAGE_SIZE=`select @@innodb_page_size`; +# Ensure that purge will not access the truncated .ibd file +--source include/wait_all_purged.inc + --source include/shutdown_mysqld.inc # Corrupt the change buffer bitmap, to claim that pages are clean @@ -84,14 +90,41 @@ EOF --replace_regex /contains \d+ entries/contains #### entries/ check table t1; ---let $restart_parameters= ---source include/restart_mysqld.inc +--source include/shutdown_mysqld.inc -# Ensure that the slow shutdown will not time out due to running purge. -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; ---source include/wait_all_purged.inc -# The change buffer merge for the injected corruption must complete -# without exceeding the 60-second shutdown_server timeout. +# Truncate the file to 5 pages, as if it were empty +perl; +do "$ENV{MTR_SUITE_DIR}/include/crc32.pl"; +my $file = "$ENV{MYSQLD_DATADIR}/test/t1.ibd"; +open(FILE, "+<$file") || die "Unable to open $file"; +binmode FILE; +my $ps= $ENV{PAGE_SIZE}; +my $pages=5; +my $page; +die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; +my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS +substr($page,46,4)=pack("N", $pages); +my $polynomial = 0x82f63b78; # CRC-32C +if ($full_crc32) +{ + my $ck = mycrc32(substr($page, 0, $ps-4), 0, $polynomial); + substr($page, $ps-4, 4) = pack("N", $ck); +} +else +{ + my $ck= pack("N",mycrc32(substr($page, 4, 22), 0, $polynomial) ^ + mycrc32(substr($page, 38, $ps - 38 - 8), 0, $polynomial)); + substr($page,0,4)=$ck; + substr($page,$ps-8,4)=$ck; +} +sysseek(FILE, 0, 0) || die "Unable to rewind $file\n"; +syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n"; +truncate(FILE, $ps * $pages); +close(FILE) || die "Unable to close $file"; +EOF + +--let $restart_parameters= +--source include/start_mysqld.inc SET GLOBAL innodb_fast_shutdown=0; --source include/restart_mysqld.inc diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index add7ad9a811..a8be235f5e2 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -48,7 +48,14 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c my_default.c file_logger.c my_dlerror.c) IF (WIN32) - SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_winthread.c my_wincond.c my_winerr.c my_winfile.c my_windac.c my_conio.c) + SET (MYSYS_SOURCES ${MYSYS_SOURCES} + my_winthread.c + my_wincond.c + my_winerr.c + my_winfile.c + my_windac.c + my_conio.c + my_win_popen.cc) ENDIF() IF(UNIX) diff --git a/mysys/my_win_popen.cc b/mysys/my_win_popen.cc new file mode 100644 index 00000000000..f41f54100f1 --- /dev/null +++ b/mysys/my_win_popen.cc @@ -0,0 +1,170 @@ +/* 2019, MariaDB Corporation. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; 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 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 */ + +/* + Replacement of the buggy implementations of popen in Windows CRT +*/ +#include <windows.h> +#include <fcntl.h> +#include <io.h> +#include <mutex> +#include <stdlib.h> +#include <unordered_map> + +enum +{ + REDIRECT_STDIN= 'w', + REDIRECT_STDOUT= 'r' +}; + +/** Map from FILE* returned by popen() to corresponding process handle.*/ +static std::unordered_map<FILE *, HANDLE> popen_map; +/* Mutex to protect the map.*/ +static std::mutex popen_mtx; + +/** +Creates a FILE* from HANDLE. +*/ +static FILE *make_fp(HANDLE *handle, const char *mode) +{ + int flags = 0; + + if (mode[0] == REDIRECT_STDOUT) + flags |= O_RDONLY; + switch (mode[1]) + { + case 't': + flags |= _O_TEXT; + break; + case 'b': + flags |= _O_BINARY; + break; + } + + int fd= _open_osfhandle((intptr_t) *handle, flags); + if (fd < 0) + return NULL; + FILE *fp= fdopen(fd, mode); + if (!fp) + { + /* Closing file descriptor also closes underlying handle.*/ + close(fd); + *handle= 0; + } + return fp; +} + +/** A home-backed version of popen(). */ +extern "C" FILE *my_win_popen(const char *cmd, const char *mode) +{ + FILE *fp(0); + char type= mode[0]; + HANDLE parent_pipe_end(0); + HANDLE child_pipe_end(0); + PROCESS_INFORMATION pi{}; + STARTUPINFO si{}; + std::string command_line; + + /* Create a pipe between this and child process.*/ + SECURITY_ATTRIBUTES sa_attr{}; + sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES); + sa_attr.bInheritHandle= TRUE; + switch (type) + { + case REDIRECT_STDIN: + if (!CreatePipe(&child_pipe_end, &parent_pipe_end, &sa_attr, 0)) + goto error; + break; + case REDIRECT_STDOUT: + if (!CreatePipe(&parent_pipe_end, &child_pipe_end, &sa_attr, 0)) + goto error; + break; + default: + /* Unknown mode, éxpected "r", "rt", "w", "wt" */ + abort(); + } + if (!SetHandleInformation(parent_pipe_end, HANDLE_FLAG_INHERIT, 0)) + goto error; + + /* Start child process with redirected output.*/ + + si.cb= sizeof(STARTUPINFO); + si.hStdError= GetStdHandle(STD_ERROR_HANDLE); + si.hStdOutput= (type == REDIRECT_STDOUT) ? child_pipe_end + : GetStdHandle(STD_OUTPUT_HANDLE); + si.hStdInput= (type == REDIRECT_STDIN) ? child_pipe_end + : GetStdHandle(STD_INPUT_HANDLE); + + si.dwFlags|= STARTF_USESTDHANDLES; + command_line.append("cmd.exe /c ").append(cmd); + + if (!CreateProcess(0, (LPSTR) command_line.c_str(), 0, 0, TRUE, 0, 0, 0, &si, + &pi)) + goto error; + + CloseHandle(pi.hThread); + CloseHandle(child_pipe_end); + child_pipe_end= 0; + + fp= make_fp(&parent_pipe_end, mode); + if (fp) + { + std::unique_lock<std::mutex> lk(popen_mtx); + popen_map[fp]= pi.hProcess; + return fp; + } + +error: + for (auto handle : { parent_pipe_end, child_pipe_end }) + { + if (handle) + CloseHandle(handle); + } + + if (pi.hProcess) + { + TerminateProcess(pi.hProcess, 1); + CloseHandle(pi.hProcess); + } + return NULL; +} + +/** A home-backed version of pclose(). */ + +extern "C" int my_win_pclose(FILE *fp) +{ + /* Find process entry for given file pointer.*/ + std::unique_lock<std::mutex> lk(popen_mtx); + HANDLE proc= popen_map[fp]; + if (!proc) + { + errno= EINVAL; + return -1; + } + popen_map.erase(fp); + lk.unlock(); + + fclose(fp); + + /* Wait for process to complete, return its exit code.*/ + DWORD ret; + if (WaitForSingleObject(proc, INFINITE) || !GetExitCodeProcess(proc, &ret)) + { + ret= -1; + errno= EINVAL; + } + CloseHandle(proc); + return ret; +} diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 10d97328c70..005f8e98868 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5479,6 +5479,13 @@ int ha_partition::index_end() if ((tmp= (*file)->ha_index_end())) error= tmp; } + else if ((*file)->inited == RND) + { + // Possible due to MRR + int tmp; + if ((tmp= (*file)->ha_rnd_end())) + error= tmp; + } } while (*(++file)); destroy_record_priority_queue(); DBUG_RETURN(error); @@ -6513,8 +6520,11 @@ int ha_partition::multi_range_read_next(range_id_t *range_info) else if (unlikely((error= handle_unordered_next(table->record[0], FALSE)))) DBUG_RETURN(error); - *range_info= - ((PARTITION_KEY_MULTI_RANGE *) m_range_info[m_last_part])->ptr; + if (!(m_mrr_mode & HA_MRR_NO_ASSOCIATION)) + { + *range_info= + ((PARTITION_KEY_MULTI_RANGE *) m_range_info[m_last_part])->ptr; + } } DBUG_RETURN(0); } diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 8c6b0de368d..4fc386a0afe 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -1703,11 +1703,10 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, } uint add_len= share->key_info[keyno].key_length + primary_file->ref_length; - *bufsz -= add_len; - if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost)) + if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, add_len, + &dsmrr_cost)) return TRUE; - *bufsz += add_len; - + bool force_dsmrr; /* If mrr_cost_based flag is not set, then set cost of DS-MRR to be minimum of @@ -1796,6 +1795,11 @@ static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate * @param rows E(Number of rows to be scanned) @param flags Scan parameters (HA_MRR_* flags) @param buffer_size INOUT Buffer size + IN: Buffer of size 0 means the function + will determine the best size and return it. + @param extra_mem_overhead Extra memory overhead of the MRR implementation + (the function assumes this many bytes of buffer + space will not be usable by DS-MRR) @param cost OUT The cost @retval FALSE OK @@ -1804,7 +1808,9 @@ static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate * */ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, - uint *buffer_size, Cost_estimate *cost) + uint *buffer_size, + uint extra_mem_overhead, + Cost_estimate *cost) { ulong max_buff_entries, elem_size; ha_rows rows_in_full_step; @@ -1814,11 +1820,24 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, elem_size= primary_file->ref_length + sizeof(void*) * (!MY_TEST(flags & HA_MRR_NO_ASSOCIATION)); - max_buff_entries = *buffer_size / elem_size; - if (!max_buff_entries) + if (!*buffer_size) + { + /* + We are requested to determine how much memory we need. + Request memory to finish the scan in one pass but do not request + more than @@mrr_buff_size. + */ + *buffer_size= (uint) MY_MIN(extra_mem_overhead + elem_size*(ulong)rows, + MY_MAX(table->in_use->variables.mrr_buff_size, + extra_mem_overhead)); + } + + if (elem_size + extra_mem_overhead > *buffer_size) return TRUE; /* Buffer has not enough space for even 1 rowid */ + max_buff_entries = (*buffer_size - extra_mem_overhead) / elem_size; + /* Number of iterations we'll make with full buffer */ n_full_steps= (uint)floor(rows2double(rows) / max_buff_entries); diff --git a/sql/multi_range_read.h b/sql/multi_range_read.h index 85578aa312c..0473fef04ae 100644 --- a/sql/multi_range_read.h +++ b/sql/multi_range_read.h @@ -631,8 +631,9 @@ private: bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz, Cost_estimate *cost); - bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, - uint *buffer_size, Cost_estimate *cost); + bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, + uint *buffer_size, uint extra_mem_overhead, + Cost_estimate *cost); bool check_cpk_scan(THD *thd, TABLE_SHARE *share, uint keyno, uint mrr_flags); bool setup_buffer_sharing(uint key_size_in_keybuf, key_part_map key_tuple_map); diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc index 915db629f44..f8b94159a8f 100644 --- a/sql/mysql_install_db.cc +++ b/sql/mysql_install_db.cc @@ -188,7 +188,7 @@ int main(int argc, char **argv) die("--datadir option not provided, and default datadir not found"); my_print_help(my_long_options); } - strncat_s(default_datadir, sizeof(default_datadir), "\\data", _TRUNCATE); + strcat_s(default_datadir, "\\data"); opt_datadir= default_datadir; printf("Default data directory is %s\n",opt_datadir); } diff --git a/sql/mysql_upgrade_service.cc b/sql/mysql_upgrade_service.cc index b612f31a289..dc4b2d0923c 100644 --- a/sql/mysql_upgrade_service.cc +++ b/sql/mysql_upgrade_service.cc @@ -511,8 +511,8 @@ int main(int argc, char **argv) die("Cannot start mysqld.exe process, last error =%u", GetLastError()); } char pipe_name[64]; - snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\mysql_upgrade_service_%u", - (uint)GetCurrentProcessId()); + snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\mysql_upgrade_service_%lu", + GetCurrentProcessId()); for (;;) { if (WaitForSingleObject(mysqld_process, 0) != WAIT_TIMEOUT) diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index afb5cf83bda..1d2c570e1a1 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -900,18 +900,12 @@ dict_create_index_tree_in_mem( /** Drop the index tree associated with a row in SYS_INDEXES table. @param[in,out] rec SYS_INDEXES record @param[in,out] pcur persistent cursor on rec -@param[in,out] mtr mini-transaction -@return whether freeing the B-tree was attempted */ -bool -dict_drop_index_tree( - rec_t* rec, - btr_pcur_t* pcur, - mtr_t* mtr) +@param[in,out] trx dictionary transaction +@param[in,out] mtr mini-transaction */ +void dict_drop_index_tree(rec_t* rec, btr_pcur_t* pcur, trx_t* trx, mtr_t* mtr) { byte* ptr; ulint len; - ulint space; - ulint root_page_no; ut_ad(mutex_own(&dict_sys.mutex)); ut_a(!dict_table_is_comp(dict_sys.sys_indexes)); @@ -922,12 +916,11 @@ dict_drop_index_tree( btr_pcur_store_position(pcur, mtr); - root_page_no = mach_read_from_4(ptr); + const uint32_t root_page_no = mach_read_from_4(ptr); if (root_page_no == FIL_NULL) { /* The tree has already been freed */ - - return(false); + return; } compile_time_assert(FIL_NULL == 0xffffffff); @@ -938,26 +931,30 @@ dict_drop_index_tree( ut_ad(len == 4); - space = mach_read_from_4(ptr); + const uint32_t space_id = mach_read_from_4(ptr); + ut_ad(space_id < SRV_TMP_SPACE_ID); + if (space_id != TRX_SYS_SPACE + && trx_get_dict_operation(trx) == TRX_DICT_OP_TABLE) { + /* We are about to delete the entire .ibd file; + do not bother to free pages inside it. */ + return; + } ptr = rec_get_nth_field_old( rec, DICT_FLD__SYS_INDEXES__ID, &len); ut_ad(len == 8); - if (fil_space_t* s = fil_space_acquire_silent(space)) { + if (fil_space_t* s = fil_space_acquire_silent(space_id)) { /* Ensure that the tablespace file exists in order to avoid a crash in buf_page_get_gen(). */ - if (s->size || fil_space_get_size(space)) { - btr_free_if_exists(page_id_t(space, root_page_no), + if (s->size || fil_space_get_size(space_id)) { + btr_free_if_exists(page_id_t(space_id, root_page_no), s->zip_size(), mach_read_from_8(ptr), mtr); } s->release(); - return true; } - - return false; } /*********************************************************************//** diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7e019ab96af..265422c28bc 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6235,7 +6235,7 @@ ha_innobase::clone( DBUG_ENTER("ha_innobase::clone"); ha_innobase* new_handler = static_cast<ha_innobase*>( - handler::clone(name, mem_root)); + handler::clone(m_prebuilt->table->name.m_name, mem_root)); if (new_handler != NULL) { DBUG_ASSERT(new_handler->m_prebuilt != NULL); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 3c5fedf1ff2..4369f2a806c 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -2407,17 +2407,21 @@ tablespace_deleted: continue; } - const ulint zip_size = s->zip_size(); + const ulint zip_size = s->zip_size(), size = s->size; s->release_for_io(); mtr_t mtr; - mtr.start(); - dberr_t err; - buf_page_get_gen(page_id_t(space_id, page_nos[i]), zip_size, - RW_X_LATCH, NULL, BUF_GET, - __FILE__, __LINE__, &mtr, &err, true); - mtr.commit(); - if (err == DB_TABLESPACE_DELETED) { - goto tablespace_deleted; + + if (UNIV_LIKELY(page_nos[i] < size)) { + mtr.start(); + dberr_t err; + buf_page_get_gen(page_id_t(space_id, page_nos[i]), + zip_size, + RW_X_LATCH, NULL, BUF_GET, + __FILE__, __LINE__, &mtr, &err, true); + mtr.commit(); + if (err == DB_TABLESPACE_DELETED) { + goto tablespace_deleted; + } } /* Prevent an infinite loop, by removing entries from the change buffer also in the case the bitmap bits were diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index ed68b7f57b8..6775154b73a 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -99,13 +99,10 @@ dict_create_index_tree( /** Drop the index tree associated with a row in SYS_INDEXES table. @param[in,out] rec SYS_INDEXES record @param[in,out] pcur persistent cursor on rec -@param[in,out] mtr mini-transaction -@return whether freeing the B-tree was attempted */ -bool -dict_drop_index_tree( - rec_t* rec, - btr_pcur_t* pcur, - mtr_t* mtr); +@param[in,out] trx dictionary transaction +@param[in,out] mtr mini-transaction */ +void dict_drop_index_tree(rec_t* rec, btr_pcur_t* pcur, trx_t* trx, mtr_t* mtr) + MY_ATTRIBUTE((nonnull)); /***************************************************************//** Creates an index tree for the index if it is not a member of a cluster. diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 70f89d9115d..341146c0a36 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -130,7 +130,8 @@ row_undo_ins_remove_clust_rec( == RW_X_LATCH); ut_ad(node->rec_type == TRX_UNDO_INSERT_REC); - dict_drop_index_tree(rec, &node->pcur, &mtr); + dict_drop_index_tree(rec, &node->pcur, node->trx, + &mtr); mtr.commit(); mtr.start(); diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index bc072ccffc9..5c71bfe4029 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -3125,7 +3125,7 @@ row_upd_clust_step( ut_ad(!dict_index_is_online_ddl(index)); dict_drop_index_tree( - btr_pcur_get_rec(pcur), pcur, &mtr); + btr_pcur_get_rec(pcur), pcur, trx, &mtr); mtr.commit(); diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 52ae6dd8e2b..a23a92ab171 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -1024,10 +1024,12 @@ can_enable_indexes(1), bulk_insert_single_undo(BULK_INSERT_NONE) {} -handler *ha_maria::clone(const char *name, MEM_ROOT *mem_root) +handler *ha_maria::clone(const char *name __attribute__((unused)), + MEM_ROOT *mem_root) { - ha_maria *new_handler= static_cast <ha_maria *>(handler::clone(name, - mem_root)); + ha_maria *new_handler= + static_cast <ha_maria *>(handler::clone(file->s->open_file_name.str, + mem_root)); if (new_handler) { new_handler->file->state= file->state; diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 78c5e58de76..04b588ef8c7 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -725,10 +725,11 @@ ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg) can_enable_indexes(1) {} -handler *ha_myisam::clone(const char *name, MEM_ROOT *mem_root) +handler *ha_myisam::clone(const char *name __attribute__((unused)), + MEM_ROOT *mem_root) { - ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(name, - mem_root)); + ha_myisam *new_handler= + static_cast <ha_myisam *>(handler::clone(file->filename, mem_root)); if (new_handler) new_handler->file->state= file->state; return new_handler; |