summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysql_upgrade.c4
-rw-r--r--client/mysqltest.cc14
-rw-r--r--extra/perror.c23
-rw-r--r--include/my_sys.h10
-rw-r--r--mysql-test/include/partition_mrr.inc46
-rw-r--r--mysql-test/main/partition_mrr_aria.result79
-rw-r--r--mysql-test/main/partition_mrr_aria.test2
-rw-r--r--mysql-test/main/partition_mrr_innodb.result79
-rw-r--r--mysql-test/main/partition_mrr_innodb.test4
-rw-r--r--mysql-test/main/partition_mrr_myisam.result79
-rw-r--r--mysql-test/main/partition_mrr_myisam.test3
-rw-r--r--mysql-test/suite/innodb/r/ibuf_not_empty.result6
-rw-r--r--mysql-test/suite/innodb/t/ibuf_not_empty.test47
-rw-r--r--mysys/CMakeLists.txt9
-rw-r--r--mysys/my_win_popen.cc170
-rw-r--r--sql/ha_partition.cc14
-rw-r--r--sql/multi_range_read.cc33
-rw-r--r--sql/multi_range_read.h5
-rw-r--r--sql/mysql_install_db.cc2
-rw-r--r--sql/mysql_upgrade_service.cc4
-rw-r--r--storage/innobase/dict/dict0crea.cc35
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc22
-rw-r--r--storage/innobase/include/dict0crea.h13
-rw-r--r--storage/innobase/row/row0uins.cc3
-rw-r--r--storage/innobase/row/row0upd.cc2
-rw-r--r--storage/maria/ha_maria.cc8
-rw-r--r--storage/myisam/ha_myisam.cc7
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;