summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicenศ›iu Ciorbaru <vicentiu@mariadb.org>2018-03-21 10:36:49 +0200
committerVicenศ›iu Ciorbaru <vicentiu@mariadb.org>2018-03-21 10:36:49 +0200
commit82aeb6b59640b9733c4026bda71887720153b70a (patch)
tree06ea8909b396e3a16042437b9574a85ee0156487
parent34b03da2114892d96af651a953f6c2527437ad15 (diff)
parenteee73ddfbb29816320c9fc78c8ff1012cac6567a (diff)
downloadmariadb-git-82aeb6b59640b9733c4026bda71887720153b70a.tar.gz
Merge branch '10.1' into 10.2
-rw-r--r--cmake/wsrep.cmake2
-rw-r--r--include/my_global.h5
-rw-r--r--mysql-test/r/ctype_latin1.result13
-rw-r--r--mysql-test/r/ctype_utf8.result13
-rw-r--r--mysql-test/r/fast_prefix_index_fetch_innodb.result361
-rw-r--r--mysql-test/r/type_time.result31
-rw-r--r--mysql-test/suite/galera/disabled.def2
-rw-r--r--mysql-test/suite/galera/include/have_wsrep_replicate_myisam.inc4
-rw-r--r--mysql-test/suite/galera/r/MW-329.result1
-rw-r--r--mysql-test/suite/galera/r/galera_defaults.result3
-rw-r--r--mysql-test/suite/galera/r/galera_flush_local.result9
-rw-r--r--mysql-test/suite/galera/r/galera_schema_dirty_reads.result13
-rw-r--r--mysql-test/suite/galera/r/galera_var_cluster_address.result3
-rw-r--r--mysql-test/suite/galera/r/galera_var_dirty_reads.result9
-rw-r--r--mysql-test/suite/galera/r/galera_var_reject_queries.result27
-rw-r--r--mysql-test/suite/galera/r/have_wsrep_replicate_myisam.require2
-rw-r--r--mysql-test/suite/galera/t/MW-329.test2
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_nonprim.test7
-rw-r--r--mysql-test/suite/galera/t/galera_concurrent_ctas.test6
-rw-r--r--mysql-test/suite/galera/t/galera_flush_local.opt4
-rw-r--r--mysql-test/suite/galera/t/galera_flush_local.test1
-rw-r--r--mysql-test/suite/galera/t/galera_schema_dirty_reads.test13
-rw-r--r--mysql-test/suite/galera/t/galera_var_cluster_address.test1
-rw-r--r--mysql-test/suite/galera/t/galera_var_dirty_reads.test3
-rw-r--r--mysql-test/suite/galera/t/galera_var_reject_queries.test44
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_wsrep.result14
-rw-r--r--mysql-test/t/ctype_latin1.test9
-rw-r--r--mysql-test/t/ctype_utf8.test10
-rw-r--r--mysql-test/t/fast_prefix_index_fetch_innodb.test664
-rw-r--r--mysql-test/t/type_time.test23
-rw-r--r--sql/item.cc14
-rw-r--r--sql/item_cmpfunc.h7
-rw-r--r--sql/sql_class.h6
-rw-r--r--sql/sql_parse.cc66
-rw-r--r--sql/sys_vars.cc12
-rw-r--r--sql/wsrep_mysqld.h7
-rw-r--r--sql/wsrep_var.cc22
-rw-r--r--sql/wsrep_var.h1
-rw-r--r--storage/innobase/buf/buf0dump.cc15
-rw-r--r--storage/innobase/os/os0file.cc2
-rw-r--r--storage/innobase/row/row0sel.cc183
-rw-r--r--storage/spider/spd_db_oracle.cc6
-rw-r--r--storage/spider/spd_direct_sql.cc16
-rw-r--r--storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result6
-rw-r--r--storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test4
-rw-r--r--storage/xtradb/buf/buf0dump.cc15
-rw-r--r--storage/xtradb/row/row0sel.cc180
47 files changed, 1566 insertions, 295 deletions
diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake
index b5dc8b9f157..9fa127380a4 100644
--- a/cmake/wsrep.cmake
+++ b/cmake/wsrep.cmake
@@ -26,7 +26,7 @@ ENDIF()
OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ${with_wsrep_default})
# Set the patch version
-SET(WSREP_PATCH_VERSION "21")
+SET(WSREP_PATCH_VERSION "23")
# Obtain wsrep API version
FILE(STRINGS "${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h" WSREP_API_VERSION
diff --git a/include/my_global.h b/include/my_global.h
index 5c325b76a7b..cdd4b503e70 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -591,6 +591,11 @@ typedef SOCKET_SIZE_TYPE size_socket;
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
+#ifdef __GLIBC__
+#define STR_O_CLOEXEC "e"
+#else
+#define STR_O_CLOEXEC ""
+#endif
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif
diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result
index b60d711568c..cbf5f145d22 100644
--- a/mysql-test/r/ctype_latin1.result
+++ b/mysql-test/r/ctype_latin1.result
@@ -8241,6 +8241,19 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c`,`test`.`t1`.`d` AS `d` from `test`.`t1` where coalesce(`test`.`t1`.`c`,0) = '3 ' and coalesce(`test`.`t1`.`d`,0) = '3 '
DROP TABLE t1;
#
+# MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple
+#
+SET NAMES latin1;
+SELECT CONVERT(1, CHAR) IN ('100', 10, '101');
+CONVERT(1, CHAR) IN ('100', 10, '101')
+0
+SELECT CONVERT(1, CHAR) IN ('100', 10, '1');
+CONVERT(1, CHAR) IN ('100', 10, '1')
+1
+SELECT CONVERT(1, CHAR) IN ('100', '10', '1');
+CONVERT(1, CHAR) IN ('100', '10', '1')
+1
+#
# End of 10.1 tests
#
#
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index f8146f9fda2..46b7386d993 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -10543,6 +10543,19 @@ CAST(_utf8 0xC499 AS CHAR CHARACTER SET latin1)
Warnings:
Warning 1977 Cannot convert 'utf8' character 0xC499 to 'latin1'
#
+# MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple
+#
+SET NAMES utf8;
+SELECT CONVERT(1, CHAR) IN ('100', 10, '101');
+CONVERT(1, CHAR) IN ('100', 10, '101')
+0
+SELECT CONVERT(1, CHAR) IN ('100', 10, '1');
+CONVERT(1, CHAR) IN ('100', 10, '1')
+1
+SELECT CONVERT(1, CHAR) IN ('100', '10', '1');
+CONVERT(1, CHAR) IN ('100', '10', '1')
+1
+#
# End of 10.1 tests
#
#
diff --git a/mysql-test/r/fast_prefix_index_fetch_innodb.result b/mysql-test/r/fast_prefix_index_fetch_innodb.result
index 92af85f7fdb..c6d96389b08 100644
--- a/mysql-test/r/fast_prefix_index_fetch_innodb.result
+++ b/mysql-test/r/fast_prefix_index_fetch_innodb.result
@@ -30,73 +30,372 @@ id fake_id bigfield
33 1033 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
128 1128 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
# Baseline sanity check: 0, 0.
+select "no-op query";
no-op query
no-op query
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
-1
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
# Eligible for optimization.
+select id, bigfield from prefixinno where bigfield = repeat('d', 31);
id bigfield
31 ddddddddddddddddddddddddddddddd
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
1
# Eligible for optimization, access via fake_id only.
+select id, bigfield from prefixinno where fake_id = 1031;
id bigfield
31 ddddddddddddddddddddddddddddddd
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
1
# Not eligible for optimization, access via fake_id of big row.
+select id, bigfield from prefixinno where fake_id = 1033;
id bigfield
33 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
# Not eligible for optimization.
+select id, bigfield from prefixinno where bigfield = repeat('x', 32);
id bigfield
32 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
# Not eligible for optimization.
+select id, bigfield from prefixinno where bigfield = repeat('y', 33);
id bigfield
33 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
# Eligible, should not increment lookup counter.
+select id, bigfield from prefixinno where bigfield = repeat('b', 8);
id bigfield
8 bbbbbbbb
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
1
# Eligible, should not increment lookup counter.
+select id, bigfield from prefixinno where bigfield = repeat('c', 24);
id bigfield
24 cccccccccccccccccccccccc
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
1
# Should increment lookup counter.
+select id, bigfield from prefixinno where bigfield = repeat('z', 128);
id bigfield
128 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
-cluster_lookups_matched
-1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
# Disable optimization, confirm we still increment counter.
+set global innodb_prefix_index_cluster_optimization = OFF;
+select id, bigfield from prefixinno where fake_id = 1033;
id bigfield
33 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
-cluster_lookups_matched
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+drop table prefixinno;
+# Multi-byte handling case
+set global innodb_prefix_index_cluster_optimization = ON;
+SET NAMES utf8mb4;
+CREATE TABLE t1(
+f1 varchar(10) CHARACTER SET UTF8MB4 COLLATE UTF8MB4_BIN,
+INDEX (f1(3)))ENGINE=INNODB;
+INSERT INTO t1 VALUES('a'), ('cccc'), ('aลพ'), ('cฤc'), ('ggแตทg'), ('ยขยข');
+INSERT INTO t1 VALUES('เฎคเฎฎเฎฟเฎดเฏ'), ('๐Ÿฑ๐ŸŒ‘'), ('๐ŸŒ’'), ('๐ŸŒ‘');
+INSERT INTO t1 VALUES('๐Ÿ˜Šme'), ('euโ‚ฌ'), ('lsยข');
+# Eligible - record length is shorter than prefix
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a';
+f1
+a
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%';
+f1
+cccc
+cฤc
+select @cluster_lookups;
+@cluster_lookups
+3
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Eligible - record length shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'aลพ';
+f1
+aลพ
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'เฎคเฎฎเฎฟเฎดเฏ';
+f1
+เฎคเฎฎเฎฟเฎดเฏ
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggแตท%';
+f1
+ggแตทg
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿ˜Š%';
+f1
+๐Ÿ˜Šme
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'lsยข';
+f1
+lsยข
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Eligible - record length shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ยขยข%';
+f1
+ยขยข
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+# Eligible - record length shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿฑ๐ŸŒ‘%';
+f1
+๐Ÿฑ๐ŸŒ‘
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ‘%';
+f1
+๐ŸŒ‘
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+2
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ’%';
+f1
+๐ŸŒ’
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+2
+DROP TABLE t1;
+# Multi-byte with minimum character length > 1 bytes
+CREATE TABLE t1(
+f1 varchar(10) CHARACTER SET UTF16 COLLATE UTF16_BIN,
+INDEX (f1(3)))ENGINE=INNODB;
+INSERT INTO t1 VALUES('a'), ('cccc'), ('aลพ'), ('cฤc'), ('ggแตทg'), ('ยขยข');
+INSERT INTO t1 VALUES('เฎคเฎฎเฎฟเฎดเฏ'), ('๐Ÿฑ๐ŸŒ‘'), ('๐ŸŒ’'), ('๐ŸŒ‘');
+INSERT INTO t1 VALUES('๐Ÿ˜Šme'), ('euโ‚ฌ'), ('lsยข');
+# Eligible - record length is shorter than prefix
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a';
+f1
+a
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%';
+f1
+cccc
+cฤc
+select @cluster_lookups;
+@cluster_lookups
+3
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Eligible - record length shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'aลพ';
+f1
+aลพ
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'เฎคเฎฎเฎฟเฎดเฏ';
+f1
+เฎคเฎฎเฎฟเฎดเฏ
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggแตท%';
+f1
+ggแตทg
+select @cluster_lookups;
+@cluster_lookups
+2
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿ˜Š%';
+f1
+๐Ÿ˜Šme
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Not eligible - record length longer than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'lsยข';
+f1
+lsยข
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Eligible - record length shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX(`f1`) WHERE f1 like 'ยขยข%';
+f1
+ยขยข
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+# Eligible - record length shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿฑ๐ŸŒ‘%';
+f1
+๐Ÿฑ๐ŸŒ‘
+select @cluster_lookups;
+@cluster_lookups
+2
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+# Eligible - record length is shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ‘%';
+f1
+๐ŸŒ‘
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+2
+# Eligible - record length is shorter than prefix length
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ’%';
+f1
+๐ŸŒ’
+select @cluster_lookups;
+@cluster_lookups
+1
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+1
+DROP TABLE t1;
+CREATE TABLE t1(
+col1 INT,
+col2 BLOB DEFAULT NULL,
+INDEX `idx1`(col2(4), col1))ENGINE=INNODB;
+INSERT INTO t1 VALUES (2, 'test'), (3, repeat('test1', 2000));
+INSERT INTO t1(col1) VALUES(1);
+# Eligible - record length is shorter than prefix length
+SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 is NULL;
+col1
1
-cluster_lookups_avoided_matched
+select @cluster_lookups;
+@cluster_lookups
+0
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
1
-# make test suite happy by cleaning up our mess
+# Not eligible - record length longer than prefix index
+SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 like 'test1%';
+col1
+3
+select @cluster_lookups;
+@cluster_lookups
+2
+select @cluster_lookups_avoided;
+@cluster_lookups_avoided
+0
+DROP TABLE t1;
+set global innodb_prefix_index_cluster_optimization = OFF;
diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index 0e627bdb915..06da656c7cb 100644
--- a/mysql-test/r/type_time.result
+++ b/mysql-test/r/type_time.result
@@ -1215,6 +1215,37 @@ MAX(a) MAX(COALESCE(a))
10:20:30 10:20:30
DROP TABLE t1;
#
+# MDEV-15321: different results when using value of optimizer_use_condition_selectivity=4 and =1
+#
+SET @save_old_mode=@@old_mode;
+SET @@old_mode=zero_date_time_cast;
+CREATE TABLE t1 (a TIME);
+INSERT INTO t1 VALUES ('0000-00-00 10:20:30'),('0000-00-00 10:20:31');
+INSERT INTO t1 VALUES ('0000-00-01 10:20:30'),('0000-00-01 10:20:31');
+INSERT INTO t1 VALUES ('31 10:20:30'),('32 10:20:30'),('33 10:20:30'),('34 10:20:30');
+SET @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
+SET @@optimizer_use_condition_selectivity=1;
+SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+a
+34:20:30
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and length(`test`.`t1`.`a`) = 8
+SET @@optimizer_use_condition_selectivity=4;
+SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+a
+34:20:30
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and length(`test`.`t1`.`a`) = 8
+drop table t1;
+SET @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
+set @@old_mode= @save_old_mode;
+#
# End of 10.1 tests
#
#
diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def
index e29e33f074e..f6bf945ed1f 100644
--- a/mysql-test/suite/galera/disabled.def
+++ b/mysql-test/suite/galera/disabled.def
@@ -10,7 +10,6 @@
#
##############################################################################
galera_gra_log : MDEV-13549 Galera test failures
-galera_flush_local : MDEV-13549 Galera test failures
galera_flush : MDEV-13549 Galera test failures
galera_account_management : MariaDB 10.0 does not support ALTER USER
galera_binlog_row_image : MariaDB 10.0 does not support binlog_row_image
@@ -30,7 +29,6 @@ galera_gcache_recover_manytrx : MDEV-13549 Galera test failures
galera_ist_mysqldump : MDEV-13549 Galera test failures
mysql-wsrep#31 : MDEV-13549 Galera test failures
galera_migrate : MariaDB 10.0 does not support START SLAVE USER
-galera_concurrent_ctas : MDEV-13549 Galera test failures
galera_wsrep_desync_wsrep_on : MDEV-13549 Galera test failures
galera_ssl_upgrade : MDEV-13549 Galera test failures
mysql-wsrep#33 : MDEV-13549 Galera test failures
diff --git a/mysql-test/suite/galera/include/have_wsrep_replicate_myisam.inc b/mysql-test/suite/galera/include/have_wsrep_replicate_myisam.inc
new file mode 100644
index 00000000000..726fc6e2b18
--- /dev/null
+++ b/mysql-test/suite/galera/include/have_wsrep_replicate_myisam.inc
@@ -0,0 +1,4 @@
+--require suite/galera/r/have_wsrep_replicate_myisam.require
+disable_query_log;
+SHOW VARIABLES LIKE 'wsrep_replicate_myisam';
+enable_query_log;
diff --git a/mysql-test/suite/galera/r/MW-329.result b/mysql-test/suite/galera/r/MW-329.result
index af57bc4b056..a3cb7277a9c 100644
--- a/mysql-test/suite/galera/r/MW-329.result
+++ b/mysql-test/suite/galera/r/MW-329.result
@@ -27,3 +27,4 @@ connection node_1;
DROP PROCEDURE proc_insert;
DROP TABLE t1;
CALL mtr.add_suppression("conflict state 3 after post commit");
+set global innodb_status_output=Default;
diff --git a/mysql-test/suite/galera/r/galera_defaults.result b/mysql-test/suite/galera/r/galera_defaults.result
index d3004735a0a..5c5fdabf432 100644
--- a/mysql-test/suite/galera/r/galera_defaults.result
+++ b/mysql-test/suite/galera/r/galera_defaults.result
@@ -1,6 +1,6 @@
SELECT COUNT(*) = 43 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
COUNT(*) = 43
-1
+0
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME LIKE 'wsrep_%'
@@ -40,6 +40,7 @@ WSREP_NOTIFY_CMD
WSREP_ON ON
WSREP_OSU_METHOD TOI
WSREP_RECOVER OFF
+WSREP_REJECT_QUERIES NONE
WSREP_REPLICATE_MYISAM OFF
WSREP_RESTART_SLAVE OFF
WSREP_RETRY_AUTOCOMMIT 1
diff --git a/mysql-test/suite/galera/r/galera_flush_local.result b/mysql-test/suite/galera/r/galera_flush_local.result
index 3fdd541b513..a8e798a693d 100644
--- a/mysql-test/suite/galera/r/galera_flush_local.result
+++ b/mysql-test/suite/galera/r/galera_flush_local.result
@@ -1,4 +1,5 @@
DROP TABLE IF EXISTS t1, t2, x1, x2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER);
CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM;
@@ -7,6 +8,8 @@ INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+connection node_2;
+connection node_1;
FLUSH LOCAL DES_KEY_FILE;
FLUSH LOCAL HOSTS;
FLUSH LOCAL QUERY CACHE;
@@ -54,6 +57,7 @@ REPAIR LOCAL TABLE x1, x2;
Table Op Msg_type Msg_text
test.x1 repair status OK
test.x2 repair status OK
+connection node_2;
wsrep_last_committed_diff
1
SELECT COUNT(*) = 10 FROM t1;
@@ -68,6 +72,7 @@ COUNT(*) = 10000
SELECT COUNT(*) = 10 FROM x2;
COUNT(*) = 10
1
+connection node_1;
DROP TABLE t1, t2, x1, x2;
CREATE TABLE t1 (f1 INTEGER);
CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
@@ -77,6 +82,8 @@ INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+connection node_2;
+connection node_1;
set wsrep_on=0;
FLUSH DES_KEY_FILE;
FLUSH HOSTS;
@@ -125,6 +132,7 @@ REPAIR TABLE x1, x2;
Table Op Msg_type Msg_text
test.x1 repair status OK
test.x2 repair status OK
+connection node_2;
wsrep_last_committed_diff
1
wsrep_last_committed_diff2
@@ -141,5 +149,6 @@ COUNT(*) = 10000
SELECT COUNT(*) = 10 FROM x2;
COUNT(*) = 10
1
+connection node_1;
set wsrep_on=1;
DROP TABLE t1, t2, x1, x2;
diff --git a/mysql-test/suite/galera/r/galera_schema_dirty_reads.result b/mysql-test/suite/galera/r/galera_schema_dirty_reads.result
new file mode 100644
index 00000000000..edf20da92c6
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_schema_dirty_reads.result
@@ -0,0 +1,13 @@
+USE information_schema;
+SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads";
+VARIABLE_NAME VARIABLE_VALUE
+WSREP_DIRTY_READS OFF
+SET GLOBAL wsrep_reject_queries=ALL;
+SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads";
+VARIABLE_NAME VARIABLE_VALUE
+WSREP_DIRTY_READS OFF
+SET GLOBAL wsrep_reject_queries=NONE;
+SET SESSION wsrep_dirty_reads=TRUE;
+SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads";
+VARIABLE_NAME VARIABLE_VALUE
+WSREP_DIRTY_READS ON
diff --git a/mysql-test/suite/galera/r/galera_var_cluster_address.result b/mysql-test/suite/galera/r/galera_var_cluster_address.result
index 81265f44397..378d8ca84f5 100644
--- a/mysql-test/suite/galera/r/galera_var_cluster_address.result
+++ b/mysql-test/suite/galera/r/galera_var_cluster_address.result
@@ -4,7 +4,8 @@ connection node_2;
SET GLOBAL wsrep_cluster_address = 'foo://';
SET SESSION wsrep_sync_wait=0;
SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
-ERROR 08S01: WSREP has not yet prepared node for application use
+COUNT(*) > 0
+1
SHOW STATUS LIKE 'wsrep_ready';
Variable_name Value
wsrep_ready OFF
diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
index beb47be1747..df54969675d 100644
--- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result
+++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
@@ -33,14 +33,15 @@ SET @@session.wsrep_dirty_reads=OFF;
SELECT i, variable_name, variable_value FROM t1, information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads" AND i = 1;
ERROR 08S01: WSREP has not yet prepared node for application use
SELECT 1;
-1
-1
+ERROR 08S01: WSREP has not yet prepared node for application use
USE information_schema;
ERROR 08S01: WSREP has not yet prepared node for application use
SELECT * FROM information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads";
-ERROR 08S01: WSREP has not yet prepared node for application use
+VARIABLE_NAME VARIABLE_VALUE
+WSREP_DIRTY_READS OFF
SELECT COUNT(*) >= 10 FROM performance_schema.events_statements_history;
-ERROR 08S01: WSREP has not yet prepared node for application use
+COUNT(*) >= 10
+1
connection node_1;
USE test;
SELECT * FROM t1;
diff --git a/mysql-test/suite/galera/r/galera_var_reject_queries.result b/mysql-test/suite/galera/r/galera_var_reject_queries.result
new file mode 100644
index 00000000000..98380238fcb
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_reject_queries.result
@@ -0,0 +1,27 @@
+CREATE TABLE t1 (f1 INTEGER);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1;
+SET SESSION wsrep_reject_queries = ALL;
+ERROR HY000: Variable 'wsrep_reject_queries' is a GLOBAL variable and should be set with SET GLOBAL
+SET GLOBAL wsrep_reject_queries = ALL;
+SELECT * FROM t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET GLOBAL wsrep_reject_queries = ALL_KILL;
+ERROR HY000: Lost connection to MySQL server during query
+connection node_1a;
+SELECT * FROM t1;
+Got one of the listed errors
+connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SELECT * FROM t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+connection node_2;
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+INSERT INTO t1 VALUES (1);
+connect node_1c, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SET GLOBAL wsrep_reject_queries = NONE;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/have_wsrep_replicate_myisam.require b/mysql-test/suite/galera/r/have_wsrep_replicate_myisam.require
new file mode 100644
index 00000000000..c55610fd049
--- /dev/null
+++ b/mysql-test/suite/galera/r/have_wsrep_replicate_myisam.require
@@ -0,0 +1,2 @@
+Variable_name Value
+wsrep_replicate_myisam ON
diff --git a/mysql-test/suite/galera/t/MW-329.test b/mysql-test/suite/galera/t/MW-329.test
index b3b4e8e921f..5baa4d14966 100644
--- a/mysql-test/suite/galera/t/MW-329.test
+++ b/mysql-test/suite/galera/t/MW-329.test
@@ -85,3 +85,5 @@ DROP TABLE t1;
# Due to MW-330, Multiple "conflict state 3 after post commit" warnings if table is dropped while SP is running
CALL mtr.add_suppression("conflict state 3 after post commit");
+
+set global innodb_status_output=Default; \ No newline at end of file
diff --git a/mysql-test/suite/galera/t/galera_as_slave_nonprim.test b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
index 46a93458271..26fec05dfe5 100644
--- a/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
+++ b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
@@ -51,7 +51,7 @@ INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
--let $value = query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1)
--connection node_3
--disable_query_log
---eval SELECT "$value" IN ("Error 'Unknown command' on query. Default database: 'test'. Query: 'BEGIN'", "Node has dropped from cluster") AS expected_error
+--eval SELECT "$value" IN ("Error 'WSREP has not yet prepared node for application use' on query. Default database: 'test'. Query: 'BEGIN'", "Node has dropped from cluster") AS expected_error
--enable_query_log
# Step #4. Bring back the async slave and restart replication
@@ -85,8 +85,9 @@ DROP TABLE t1;
STOP SLAVE;
RESET SLAVE ALL;
-CALL mtr.add_suppression("Slave SQL: Error 'Unknown command' on query");
-CALL mtr.add_suppression("Slave: Unknown command Error_code: 1047");
+CALL mtr.add_suppression("Slave SQL: Error 'WSREP has not yet prepared node for application use' on query");
+CALL mtr.add_suppression("Slave: WSREP has not yet prepared node for application use Error_code: 1047");
+CALL mtr.add_suppression("TORDERED} returned -107 \\(Transport endpoint is not connected\\)");
CALL mtr.add_suppression("Transport endpoint is not connected");
CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed, 'Deadlock found when trying to get lock; try restarting transaction', Error_code: 1213");
CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
diff --git a/mysql-test/suite/galera/t/galera_concurrent_ctas.test b/mysql-test/suite/galera/t/galera_concurrent_ctas.test
index f0dcf8e4900..6c4e8be68a7 100644
--- a/mysql-test/suite/galera/t/galera_concurrent_ctas.test
+++ b/mysql-test/suite/galera/t/galera_concurrent_ctas.test
@@ -43,9 +43,9 @@ let $run=10;
while($run)
{
--error 0,1
- exec $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_1 test
- < $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql &
- $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_2 test
+ exec $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_1 test \
+ < $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql & \
+ $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_2 test \
< $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql;
dec $run;
}
diff --git a/mysql-test/suite/galera/t/galera_flush_local.opt b/mysql-test/suite/galera/t/galera_flush_local.opt
index 5a1fb6748d9..a084db15c5d 100644
--- a/mysql-test/suite/galera/t/galera_flush_local.opt
+++ b/mysql-test/suite/galera/t/galera_flush_local.opt
@@ -1 +1,3 @@
---query_cache_type=1 --query_cache_size=1000000
+--query_cache_type=1
+--query_cache_size=1000000
+--wsrep_replicate_myisam=ON
diff --git a/mysql-test/suite/galera/t/galera_flush_local.test b/mysql-test/suite/galera/t/galera_flush_local.test
index 768f4ea4f1b..24acd9ec4ff 100644
--- a/mysql-test/suite/galera/t/galera_flush_local.test
+++ b/mysql-test/suite/galera/t/galera_flush_local.test
@@ -5,6 +5,7 @@
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/have_query_cache.inc
+--source include/have_wsrep_replicate_myisam.inc
--disable_warnings
DROP TABLE IF EXISTS t1, t2, x1, x2;
diff --git a/mysql-test/suite/galera/t/galera_schema_dirty_reads.test b/mysql-test/suite/galera/t/galera_schema_dirty_reads.test
new file mode 100644
index 00000000000..93e24244611
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_schema_dirty_reads.test
@@ -0,0 +1,13 @@
+#
+# Dirty reads from INFORMATION_SCHEMA tables.
+#
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--disable_info
+USE information_schema;
+SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads";
+SET GLOBAL wsrep_reject_queries=ALL;
+SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads";
+SET GLOBAL wsrep_reject_queries=NONE;
+SET SESSION wsrep_dirty_reads=TRUE;
+SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads";
diff --git a/mysql-test/suite/galera/t/galera_var_cluster_address.test b/mysql-test/suite/galera/t/galera_var_cluster_address.test
index 03706bbbb12..6d99d35cdac 100644
--- a/mysql-test/suite/galera/t/galera_var_cluster_address.test
+++ b/mysql-test/suite/galera/t/galera_var_cluster_address.test
@@ -24,7 +24,6 @@ SET GLOBAL wsrep_cluster_address = 'foo://';
SET SESSION wsrep_sync_wait=0;
---error ER_UNKNOWN_COM_ERROR
SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
# Must return 'OFF'
diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
index cba8488b879..85d759e4a27 100644
--- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test
+++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
@@ -47,15 +47,14 @@ SET @@session.wsrep_dirty_reads=OFF;
--error ER_UNKNOWN_COM_ERROR
SELECT i, variable_name, variable_value FROM t1, information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads" AND i = 1;
+--error ER_UNKNOWN_COM_ERROR
SELECT 1;
--error ER_UNKNOWN_COM_ERROR
USE information_schema;
---error ER_UNKNOWN_COM_ERROR
SELECT * FROM information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads";
---error ER_UNKNOWN_COM_ERROR
SELECT COUNT(*) >= 10 FROM performance_schema.events_statements_history;
--disable_query_log
diff --git a/mysql-test/suite/galera/t/galera_var_reject_queries.test b/mysql-test/suite/galera/t/galera_var_reject_queries.test
new file mode 100644
index 00000000000..b1af9d8aa2b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_reject_queries.test
@@ -0,0 +1,44 @@
+#
+# Test wsrep_reject_queries
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--connection node_1
+--error ER_GLOBAL_VARIABLE
+SET SESSION wsrep_reject_queries = ALL;
+
+SET GLOBAL wsrep_reject_queries = ALL;
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT * FROM t1;
+
+# Lost connection
+--error 2013
+SET GLOBAL wsrep_reject_queries = ALL_KILL;
+
+--connection node_1a
+--error ER_CONNECTION_KILLED,2013
+SELECT * FROM t1;
+
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--error ER_UNKNOWN_COM_ERROR
+SELECT * FROM t1;
+
+# Confirm that replication continues
+
+--connection node_2
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+INSERT INTO t1 VALUES (1);
+
+--connect node_1c, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET GLOBAL wsrep_reject_queries = NONE;
+
+SELECT COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
index 0c206975c29..db932ae8223 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
@@ -421,6 +421,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY YES
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME WSREP_REJECT_QUERIES
+SESSION_VALUE NULL
+GLOBAL_VALUE NONE
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE NONE
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE ENUM
+VARIABLE_COMMENT Variable to set to reject queries
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST NONE,ALL,ALL_KILL
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME WSREP_REPLICATE_MYISAM
SESSION_VALUE NULL
GLOBAL_VALUE OFF
diff --git a/mysql-test/t/ctype_latin1.test b/mysql-test/t/ctype_latin1.test
index 31d4ff7f802..38f147708b8 100644
--- a/mysql-test/t/ctype_latin1.test
+++ b/mysql-test/t/ctype_latin1.test
@@ -392,6 +392,15 @@ SELECT * FROM t1 WHERE COALESCE(c,0)='3 ' AND COALESCE(d,0)=COALESCE(c,0);
DROP TABLE t1;
--echo #
+--echo # MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple
+--echo #
+
+SET NAMES latin1;
+SELECT CONVERT(1, CHAR) IN ('100', 10, '101');
+SELECT CONVERT(1, CHAR) IN ('100', 10, '1');
+SELECT CONVERT(1, CHAR) IN ('100', '10', '1');
+
+--echo #
--echo # End of 10.1 tests
--echo #
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index b6d2dc7d874..e293cae930a 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -2034,6 +2034,16 @@ SELECT CAST(_utf8 0xC499 AS CHAR CHARACTER SET latin1);
--echo #
+--echo # MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple
+--echo #
+
+SET NAMES utf8;
+SELECT CONVERT(1, CHAR) IN ('100', 10, '101');
+SELECT CONVERT(1, CHAR) IN ('100', 10, '1');
+SELECT CONVERT(1, CHAR) IN ('100', '10', '1');
+
+
+--echo #
--echo # End of 10.1 tests
--echo #
diff --git a/mysql-test/t/fast_prefix_index_fetch_innodb.test b/mysql-test/t/fast_prefix_index_fetch_innodb.test
index e563e65ec2a..c3b3440d82d 100644
--- a/mysql-test/t/fast_prefix_index_fetch_innodb.test
+++ b/mysql-test/t/fast_prefix_index_fetch_innodb.test
@@ -31,120 +31,638 @@ select * from prefixinno;
let $show_count_statement = show status like 'innodb_secondary_index_triggered_cluster_reads';
let $show_opt_statement = show status like 'innodb_secondary_index_triggered_cluster_reads_avoided';
---disable_query_log
-
--echo # Baseline sanity check: 0, 0.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select "no-op query";
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Eligible for optimization.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where bigfield = repeat('d', 31);
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Eligible for optimization, access via fake_id only.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where fake_id = 1031;
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Not eligible for optimization, access via fake_id of big row.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where fake_id = 1033;
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Not eligible for optimization.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where bigfield = repeat('x', 32);
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Not eligible for optimization.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where bigfield = repeat('y', 33);
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Eligible, should not increment lookup counter.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where bigfield = repeat('b', 8);
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Eligible, should not increment lookup counter.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where bigfield = repeat('c', 24);
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Should increment lookup counter.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
select id, bigfield from prefixinno where bigfield = repeat('z', 128);
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
--echo # Disable optimization, confirm we still increment counter.
---let $base_count = query_get_value($show_count_statement, Value, 1)
---let $base_opt = query_get_value($show_opt_statement, Value, 1)
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
set global innodb_prefix_index_cluster_optimization = OFF;
select id, bigfield from prefixinno where fake_id = 1033;
---let $count = query_get_value($show_count_statement, Value, 1)
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
eval select $count - $base_count into @cluster_lookups;
-select @cluster_lookups = 1 as cluster_lookups_matched;
---let $opt = query_get_value($show_opt_statement, Value, 1)
-eval select $opt - $base_opt into @cluster_lookups;
-select @cluster_lookups = 0 as cluster_lookups_avoided_matched;
+eval select $opt - $base_opt into @cluster_lookups_avoided;
+--enable_query_log
+select @cluster_lookups;
+select @cluster_lookups_avoided;
---echo # make test suite happy by cleaning up our mess
drop table prefixinno;
+
+--echo # Multi-byte handling case
+
+set global innodb_prefix_index_cluster_optimization = ON;
+SET NAMES utf8mb4;
+CREATE TABLE t1(
+ f1 varchar(10) CHARACTER SET UTF8MB4 COLLATE UTF8MB4_BIN,
+ INDEX (f1(3)))ENGINE=INNODB;
+
+INSERT INTO t1 VALUES('a'), ('cccc'), ('aลพ'), ('cฤc'), ('ggแตทg'), ('ยขยข');
+INSERT INTO t1 VALUES('เฎคเฎฎเฎฟเฎดเฏ'), ('๐Ÿฑ๐ŸŒ‘'), ('๐ŸŒ’'), ('๐ŸŒ‘');
+INSERT INTO t1 VALUES('๐Ÿ˜Šme'), ('euโ‚ฌ'), ('lsยข');
+
+--echo # Eligible - record length is shorter than prefix
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length shorter than prefix length
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'aลพ';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'เฎคเฎฎเฎฟเฎดเฏ';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggแตท%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿ˜Š%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'lsยข';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ยขยข%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿฑ๐ŸŒ‘%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ‘%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ’%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+DROP TABLE t1;
+
+--echo # Multi-byte with minimum character length > 1 bytes
+
+CREATE TABLE t1(
+ f1 varchar(10) CHARACTER SET UTF16 COLLATE UTF16_BIN,
+ INDEX (f1(3)))ENGINE=INNODB;
+
+INSERT INTO t1 VALUES('a'), ('cccc'), ('aลพ'), ('cฤc'), ('ggแตทg'), ('ยขยข');
+INSERT INTO t1 VALUES('เฎคเฎฎเฎฟเฎดเฏ'), ('๐Ÿฑ๐ŸŒ‘'), ('๐ŸŒ’'), ('๐ŸŒ‘');
+INSERT INTO t1 VALUES('๐Ÿ˜Šme'), ('euโ‚ฌ'), ('lsยข');
+
+--echo # Eligible - record length is shorter than prefix
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'aลพ';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'เฎคเฎฎเฎฟเฎดเฏ';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggแตท%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿ˜Š%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'lsยข';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX(`f1`) WHERE f1 like 'ยขยข%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐Ÿฑ๐ŸŒ‘%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length is shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ‘%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Eligible - record length is shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '๐ŸŒ’%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+DROP TABLE t1;
+
+CREATE TABLE t1(
+ col1 INT,
+ col2 BLOB DEFAULT NULL,
+ INDEX `idx1`(col2(4), col1))ENGINE=INNODB;
+INSERT INTO t1 VALUES (2, 'test'), (3, repeat('test1', 2000));
+INSERT INTO t1(col1) VALUES(1);
+
+--echo # Eligible - record length is shorter than prefix length
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 is NULL;
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+--echo # Not eligible - record length longer than prefix index
+
+let $base_count = query_get_value($show_count_statement, Value, 1);
+let $base_opt = query_get_value($show_opt_statement, Value, 1);
+
+SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 like 'test1%';
+
+let $count = query_get_value($show_count_statement, Value, 1);
+let $opt = query_get_value($show_opt_statement, Value, 1);
+
+--disable_query_log
+eval set @cluster_lookups = $count - $base_count;
+eval set @cluster_lookups_avoided = $opt - $base_opt;
+--enable_query_log
+
+select @cluster_lookups;
+select @cluster_lookups_avoided;
+
+DROP TABLE t1;
set global innodb_prefix_index_cluster_optimization = OFF;
diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test
index ab496408c32..cce5900a993 100644
--- a/mysql-test/t/type_time.test
+++ b/mysql-test/t/type_time.test
@@ -724,6 +724,29 @@ SELECT MAX(a), MAX(COALESCE(a)) FROM t1;
DROP TABLE t1;
--echo #
+--echo # MDEV-15321: different results when using value of optimizer_use_condition_selectivity=4 and =1
+--echo #
+
+SET @save_old_mode=@@old_mode;
+SET @@old_mode=zero_date_time_cast;
+CREATE TABLE t1 (a TIME);
+INSERT INTO t1 VALUES ('0000-00-00 10:20:30'),('0000-00-00 10:20:31');
+INSERT INTO t1 VALUES ('0000-00-01 10:20:30'),('0000-00-01 10:20:31');
+INSERT INTO t1 VALUES ('31 10:20:30'),('32 10:20:30'),('33 10:20:30'),('34 10:20:30');
+
+SET @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
+SET @@optimizer_use_condition_selectivity=1;
+SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+
+SET @@optimizer_use_condition_selectivity=4;
+SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8;
+drop table t1;
+SET @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
+set @@old_mode= @save_old_mode;
+
+--echo #
--echo # End of 10.1 tests
--echo #
diff --git a/sql/item.cc b/sql/item.cc
index 8dce7f7c64a..dead75f548c 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -179,19 +179,21 @@ bool Item::get_time_with_conversion(THD *thd, MYSQL_TIME *ltime,
- truncate the YYYYMMDD part
- add (MM*33+DD)*24 to hours
- add (MM*31+DD)*24 to hours
- Let's return NULL here, to disallow equal field propagation.
+ Let's return TRUE here, to disallow equal field propagation.
Note, If we start to use this method in more pieces of the code other
- than eqial field propagation, we should probably return
- NULL only if some flag in fuzzydate is set.
+ than equal field propagation, we should probably return
+ TRUE only if some flag in fuzzydate is set.
*/
- return (null_value= true);
+ return true;
}
if (datetime_to_time_with_warn(thd, ltime, &ltime2, TIME_SECOND_PART_DIGITS))
{
/*
- Time difference between CURRENT_DATE and ltime
- did not fit into the supported TIME range
+ If the time difference between CURRENT_DATE and ltime
+ did not fit into the supported TIME range, then we set the
+ difference to the maximum possible value in the supported TIME range
*/
+ DBUG_ASSERT(0);
return (null_value= true);
}
*ltime= ltime2;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index ced3f343707..5f3bd1e4ca7 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1383,6 +1383,13 @@ public:
{
value_res= item->val_str(&value);
m_null_value= item->null_value;
+ // Make sure to cache the result String inside "value"
+ if (value_res && value_res != &value)
+ {
+ if (value.copy(*value_res))
+ value.set("", 0, item->collation.collation);
+ value_res= &value;
+ }
}
int cmp(Item *arg)
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d4546a0c550..89cdb5af251 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5726,11 +5726,15 @@ public:
sent by the user (ie: stored procedure).
*/
#define CF_SKIP_QUESTIONS (1U << 1)
-
+#ifdef WITH_WSREP
/**
Do not check that wsrep snapshot is ready before allowing this command
*/
#define CF_SKIP_WSREP_CHECK (1U << 2)
+#else
+#define CF_SKIP_WSREP_CHECK 0
+#endif /* WITH_WSREP */
+
/**
Do not allow it for COM_MULTI batch
*/
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b4196dafee1..96f6196bc08 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2008, 2017, MariaDB
+ Copyright (c) 2008, 2018, MariaDB
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
@@ -506,6 +506,7 @@ void init_update_queries(void)
server_command_flags[COM_SHUTDOWN]= CF_SKIP_WSREP_CHECK;
server_command_flags[COM_SLEEP]= CF_SKIP_WSREP_CHECK;
server_command_flags[COM_TIME]= CF_SKIP_WSREP_CHECK;
+ server_command_flags[COM_INIT_DB]= CF_SKIP_WSREP_CHECK;
server_command_flags[COM_END]= CF_SKIP_WSREP_CHECK;
for (uint i= COM_MDB_GAP_BEG; i <= COM_MDB_GAP_END; i++)
{
@@ -519,6 +520,8 @@ void init_update_queries(void)
server_command_flags[COM_QUERY]= CF_SKIP_WSREP_CHECK;
server_command_flags[COM_SET_OPTION]= CF_SKIP_WSREP_CHECK;
server_command_flags[COM_STMT_PREPARE]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK;
+ server_command_flags[COM_STMT_EXECUTE]= CF_SKIP_WSREP_CHECK;
+ server_command_flags[COM_STMT_FETCH]= CF_SKIP_WSREP_CHECK;
server_command_flags[COM_STMT_CLOSE]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK;
server_command_flags[COM_STMT_RESET]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK;
server_command_flags[COM_STMT_EXECUTE]= CF_SKIP_WSREP_CHECK;
@@ -1146,21 +1149,28 @@ static enum enum_server_command fetch_command(THD *thd, char *packet)
}
-#ifndef EMBEDDED_LIBRARY
-
#ifdef WITH_WSREP
-static bool wsrep_node_is_ready(THD *thd)
+static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables)
{
- if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready)
+ bool has_tables = false;
+ for (const TABLE_LIST *table= tables; table; table= table->next_global)
{
- my_message(ER_UNKNOWN_COM_ERROR,
- "WSREP has not yet prepared node for application use",
- MYF(0));
- return false;
+ TABLE_CATEGORY c;
+ LEX_STRING db, tn;
+ lex_string_set(&db, table->db);
+ lex_string_set(&tn, table->table_name);
+ c= get_table_category(&db, &tn);
+ if (c != TABLE_CATEGORY_INFORMATION &&
+ c != TABLE_CATEGORY_PERFORMANCE)
+ {
+ return false;
+ }
+ has_tables = true;
}
- return true;
+ return has_tables;
}
-#endif
+#endif /* WITH_WSREP */
+#ifndef EMBEDDED_LIBRARY
/**
Read one command from connection and execute it (query or simple command).
@@ -1336,8 +1346,9 @@ bool do_command(THD *thd)
/*
Bail out if DB snapshot has not been installed.
*/
- if (!(server_command_flags[command] & CF_SKIP_WSREP_CHECK) &&
- !wsrep_node_is_ready(thd))
+ if (thd->variables.wsrep_on && !thd->wsrep_applier &&
+ (!wsrep_ready || wsrep_reject_queries != WSREP_REJECT_NONE) &&
+ (server_command_flags[command] & CF_SKIP_WSREP_CHECK) == 0)
{
thd->protocol->end_statement();
@@ -3143,20 +3154,23 @@ mysql_execute_command(THD *thd)
}
/*
- Bail out if DB snapshot has not been installed. SET and SHOW commands,
- however, are always allowed.
- Select query is also allowed if it does not access any table.
- We additionally allow all other commands that do not change data in
- case wsrep_dirty_reads is enabled.
- */
- if (lex->sql_command != SQLCOM_SET_OPTION &&
- !wsrep_is_show_query(lex->sql_command) &&
- !(thd->variables.wsrep_dirty_reads &&
- !is_update_query(lex->sql_command)) &&
- !(lex->sql_command == SQLCOM_SELECT &&
- !all_tables) &&
- !wsrep_node_is_ready(thd))
+ * Bail out if DB snapshot has not been installed. We however,
+ * allow SET and SHOW queries and reads from information schema
+ * and dirty reads (if configured)
+ */
+ if (thd->variables.wsrep_on &&
+ !thd->wsrep_applier &&
+ !(wsrep_ready && wsrep_reject_queries == WSREP_REJECT_NONE) &&
+ !(thd->variables.wsrep_dirty_reads &&
+ (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) == 0) &&
+ !wsrep_tables_accessible_when_detached(all_tables) &&
+ lex->sql_command != SQLCOM_SET_OPTION &&
+ !wsrep_is_show_query(lex->sql_command))
+ {
+ my_message(ER_UNKNOWN_COM_ERROR,
+ "WSREP has not yet prepared node for application use", MYF(0));
goto error;
+ }
}
#endif /* WITH_WSREP */
status_var_increment(thd->status_var.com_stat[lex->sql_command]);
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index ea95899b004..a640bc40f85 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1,7 +1,7 @@
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
- Copyright (c) 2012, 2017, MariaDB Corporation.
+ Copyright (c) 2012, 2018, MariaDB Corporation.
- This program is free software; you can redistribute it and/or modify
+ 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.
@@ -5077,6 +5077,14 @@ static Sys_var_mybool Sys_wsrep_desync (
ON_CHECK(wsrep_desync_check),
ON_UPDATE(wsrep_desync_update));
+static const char *wsrep_reject_queries_names[]= { "NONE", "ALL", "ALL_KILL", NullS };
+static Sys_var_enum Sys_wsrep_reject_queries(
+ "wsrep_reject_queries", "Variable to set to reject queries",
+ GLOBAL_VAR(wsrep_reject_queries), CMD_LINE(OPT_ARG),
+ wsrep_reject_queries_names, DEFAULT(WSREP_REJECT_NONE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(wsrep_reject_queries_update));
+
static const char *wsrep_binlog_format_names[]=
{"MIXED", "STATEMENT", "ROW", "NONE", NullS};
static Sys_var_enum Sys_wsrep_forced_binlog_format(
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index f154b51516b..eb37b63eff6 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -80,6 +80,7 @@ extern const char* wsrep_notify_cmd;
extern long wsrep_max_protocol_version;
extern ulong wsrep_forced_binlog_format;
extern my_bool wsrep_desync;
+extern ulong wsrep_reject_queries;
extern my_bool wsrep_replicate_myisam;
extern ulong wsrep_mysql_replication_bundle;
extern my_bool wsrep_restart_slave;
@@ -91,6 +92,12 @@ extern bool wsrep_new_cluster;
extern bool wsrep_gtid_mode;
extern uint32 wsrep_gtid_domain_id;
+enum enum_wsrep_reject_types {
+ WSREP_REJECT_NONE, /* nothing rejected */
+ WSREP_REJECT_ALL, /* reject all queries, with UNKNOWN_COMMAND error */
+ WSREP_REJECT_ALL_KILL /* kill existing connections and reject all queries*/
+};
+
enum enum_wsrep_OSU_method {
WSREP_OSU_TOI,
WSREP_OSU_RSU,
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index b9eb546bf76..38d727fb470 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -26,6 +26,7 @@
#include <cstdio>
#include <cstdlib>
+ulong wsrep_reject_queries;
static long wsrep_prev_slave_threads = wsrep_slave_threads;
@@ -413,6 +414,27 @@ void wsrep_provider_options_init(const char* value)
wsrep_provider_options = (value) ? my_strdup(value, MYF(0)) : NULL;
}
+bool wsrep_reject_queries_update(sys_var *self, THD* thd, enum_var_type type)
+{
+ switch (wsrep_reject_queries) {
+ case WSREP_REJECT_NONE:
+ WSREP_INFO("Allowing client queries due to manual setting");
+ break;
+ case WSREP_REJECT_ALL:
+ WSREP_INFO("Rejecting client queries due to manual setting");
+ break;
+ case WSREP_REJECT_ALL_KILL:
+ wsrep_close_client_connections(FALSE);
+ WSREP_INFO("Rejecting client queries and killing connections due to manual setting");
+ break;
+ default:
+ WSREP_INFO("Unknown value for wsrep_reject_queries: %lu",
+ wsrep_reject_queries);
+ return true;
+ }
+ return false;
+}
+
static int wsrep_cluster_address_verify (const char* cluster_address_str)
{
/* There is no predefined address format, it depends on provider. */
diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h
index b9051b29843..7d3ff50f1d2 100644
--- a/sql/wsrep_var.h
+++ b/sql/wsrep_var.h
@@ -92,6 +92,7 @@ extern bool wsrep_desync_update UPDATE_ARGS;
extern bool wsrep_max_ws_size_check CHECK_ARGS;
extern bool wsrep_max_ws_size_update UPDATE_ARGS;
+extern bool wsrep_reject_queries_update UPDATE_ARGS;
#else /* WITH_WSREP */
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index 6cd8111e902..903f1f13ace 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -275,7 +275,20 @@ buf_dump(
buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) to %s",
full_filename);
- f = fopen(tmp_filename, "w");
+#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
+ f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
+#else
+ {
+ int fd;
+ fd = open(tmp_filename, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, 0640);
+ if (fd >= 0) {
+ f = fdopen(fd, "w");
+ }
+ else {
+ f = NULL;
+ }
+ }
+#endif
if (f == NULL) {
buf_dump_status(STATUS_ERR,
"Cannot open '%s' for writing: %s",
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index a824afc6e0e..14bd79a0c5d 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -2255,7 +2255,7 @@ AIO::is_linux_native_aio_supported()
strcpy(name + dirnamelen, "ib_logfile0");
- fd = open(name, O_RDONLY);
+ fd = open(name, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index c42b08d820b..9f14be17c11 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -2915,7 +2915,9 @@ row_sel_field_store_in_mysql_format_func(
|| !(templ->mysql_col_len % templ->mbmaxlen));
ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len
|| (field_no == templ->icp_rec_field_no
- && field->prefix_len > 0));
+ && field->prefix_len > 0)
+ || templ->rec_field_is_prefix);
+
ut_ad(templ->is_virtual
|| !(field->prefix_len % templ->mbmaxlen));
@@ -4061,6 +4063,118 @@ row_sel_fill_vrow(
}
}
+/** Return the record field length in characters.
+@param[in] col table column of the field
+@param[in] field_no field number
+@param[in] rec physical record
+@param[in] offsets field offsets in the physical record
+@return field length in characters. */
+static
+size_t
+rec_field_len_in_chars(
+ const dict_col_t* col,
+ const ulint field_no,
+ const rec_t* rec,
+ const ulint* offsets)
+{
+ const ulint cset = dtype_get_charset_coll(col->prtype);
+ const CHARSET_INFO* cs = all_charsets[cset];
+ ulint rec_field_len;
+ const char* rec_field = reinterpret_cast<const char *>(
+ rec_get_nth_field(
+ rec, offsets, field_no, &rec_field_len));
+
+ if (UNIV_UNLIKELY(!cs)) {
+ ib::warn() << "Missing collation " << cset;
+ return SIZE_T_MAX;
+ }
+
+ return(cs->cset->numchars(cs, rec_field, rec_field + rec_field_len));
+}
+
+/** Avoid the clustered index lookup if all the following conditions
+are true:
+1) all columns are in secondary index
+2) all values for columns that are prefix-only indexes are shorter
+than the prefix size. This optimization can avoid many IOs for certain schemas.
+@return true, to avoid clustered index lookup. */
+static
+bool row_search_with_covering_prefix(
+ row_prebuilt_t* prebuilt,
+ const rec_t* rec,
+ const ulint* offsets)
+{
+ const dict_index_t* index = prebuilt->index;
+ ut_ad(!dict_index_is_clust(index));
+
+ if (!srv_prefix_index_cluster_optimization) {
+ return false;
+ }
+
+ /** Optimization only applicable if there the number of secondary index
+ fields are greater than or equal to number of clustered index fields. */
+ if (prebuilt->n_template > index->n_fields) {
+ return false;
+ }
+
+ for (ulint i = 0; i < prebuilt->n_template; i++) {
+ mysql_row_templ_t* templ = prebuilt->mysql_template + i;
+ ulint j = templ->rec_prefix_field_no;
+
+ /** Condition (1) : is the field in the index. */
+ if (j == ULINT_UNDEFINED) {
+ return false;
+ }
+
+ /** Condition (2): If this is a prefix index then
+ row's value size shorter than prefix length. */
+
+ if (!templ->rec_field_is_prefix) {
+ continue;
+ }
+
+ ulint rec_size = rec_offs_nth_size(offsets, j);
+ const dict_field_t* field = dict_index_get_nth_field(index, j);
+ ulint max_chars = field->prefix_len / templ->mbmaxlen;
+
+ ut_a(field->prefix_len > 0);
+
+ if (rec_size < max_chars) {
+ /* Record in bytes shorter than the index
+ prefix length in char. */
+ continue;
+ }
+
+ if (rec_size * templ->mbminlen >= field->prefix_len) {
+ /* Shortest representation string by the
+ byte length of the record is longer than the
+ maximum possible index prefix. */
+ return false;
+ }
+
+ size_t num_chars = rec_field_len_in_chars(
+ field->col, j, rec, offsets);
+
+ if (num_chars >= max_chars) {
+ /* No of chars to store the record exceeds
+ the index prefix character length. */
+ return false;
+ }
+ }
+
+ /* If prefix index optimization condition satisfied then
+ for all columns above, use rec_prefix_field_no instead of
+ rec_field_no, and skip the clustered lookup below. */
+ for (ulint i = 0; i < prebuilt->n_template; i++) {
+ mysql_row_templ_t* templ = prebuilt->mysql_template + i;
+ templ->rec_field_no = templ->rec_prefix_field_no;
+ ut_a(templ->rec_field_no != ULINT_UNDEFINED);
+ }
+
+ srv_stats.n_sec_rec_cluster_reads_avoided.inc();
+ return true;
+}
+
/** Searches for rows in the database using cursor.
Function is mainly used for tables that are shared across connections and
so it employs technique that can help re-construct the rows that
@@ -4120,7 +4234,6 @@ row_search_mvcc(
ulint* offsets = offsets_;
ibool table_lock_waited = FALSE;
byte* next_buf = 0;
- ibool use_clustered_index = FALSE;
bool spatial_search = false;
rec_offs_init(offsets_);
@@ -5179,69 +5292,10 @@ locks_ok_del_marked:
break;
}
- /* Get the clustered index record if needed, if we did not do the
- search using the clustered index... */
-
- use_clustered_index =
- (index != clust_index && prebuilt->need_to_access_clustered);
-
- if (use_clustered_index && srv_prefix_index_cluster_optimization
- && prebuilt->n_template <= index->n_fields) {
- /* ...but, perhaps avoid the clustered index lookup if
- all of the following are true:
- 1) all columns are in the secondary index
- 2) all values for columns that are prefix-only
- indexes are shorter than the prefix size
- This optimization can avoid many IOs for certain schemas.
- */
- ibool row_contains_all_values = TRUE;
- uint i;
- for (i = 0; i < prebuilt->n_template; i++) {
- /* Condition (1) from above: is the field in the
- index (prefix or not)? */
- mysql_row_templ_t* templ =
- prebuilt->mysql_template + i;
- ulint secondary_index_field_no =
- templ->rec_prefix_field_no;
- if (secondary_index_field_no == ULINT_UNDEFINED) {
- row_contains_all_values = FALSE;
- break;
- }
- /* Condition (2) from above: if this is a
- prefix, is this row's value size shorter
- than the prefix? */
- if (templ->rec_field_is_prefix) {
- ulint record_size = rec_offs_nth_size(
- offsets,
- secondary_index_field_no);
- const dict_field_t *field =
- dict_index_get_nth_field(
- index,
- secondary_index_field_no);
- ut_a(field->prefix_len > 0);
- if (record_size >= field->prefix_len) {
- row_contains_all_values = FALSE;
- break;
- }
- }
+ if (index != clust_index && prebuilt->need_to_access_clustered) {
+ if (row_search_with_covering_prefix(prebuilt, rec, offsets)) {
+ goto use_covering_index;
}
- /* If (1) and (2) were true for all columns above, use
- rec_prefix_field_no instead of rec_field_no, and skip
- the clustered lookup below. */
- if (row_contains_all_values) {
- for (i = 0; i < prebuilt->n_template; i++) {
- mysql_row_templ_t* templ =
- prebuilt->mysql_template + i;
- templ->rec_field_no =
- templ->rec_prefix_field_no;
- ut_a(templ->rec_field_no != ULINT_UNDEFINED);
- }
- use_clustered_index = FALSE;
- srv_stats.n_sec_rec_cluster_reads_avoided.inc();
- }
- }
-
- if (use_clustered_index) {
requires_clust_rec:
ut_ad(index != clust_index);
/* We use a 'goto' to the preceding label if a consistent
@@ -5339,6 +5393,7 @@ requires_clust_rec:
}
}
} else {
+use_covering_index:
result_rec = rec;
}
diff --git a/storage/spider/spd_db_oracle.cc b/storage/spider/spd_db_oracle.cc
index 94f354e0a0f..e6e5dc7c109 100644
--- a/storage/spider/spd_db_oracle.cc
+++ b/storage/spider/spd_db_oracle.cc
@@ -29,6 +29,10 @@
#endif
#ifdef HAVE_ORACLE_OCI
+#if (defined(WIN32) || defined(_WIN32) || defined(WINDOWS) || defined(_WINDOWS))
+#include <Shlwapi.h>
+#define strcasestr StrStr
+#endif
#include <oci.h>
#include "spd_err.h"
#include "spd_param.h"
@@ -3817,7 +3821,7 @@ int spider_db_oracle_util::open_item_func(
{
Item_func_conv_charset *item_func_conv_charset =
(Item_func_conv_charset *)item_func;
- CHARSET_INFO *conv_charset = item_func_conv_charset->conv_charset;
+ CHARSET_INFO *conv_charset = item_func_conv_charset->collation.collation;
uint cset_length = strlen(conv_charset->csname);
if (str->reserve(SPIDER_SQL_USING_LEN + cset_length))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
diff --git a/storage/spider/spd_direct_sql.cc b/storage/spider/spd_direct_sql.cc
index dc1786796e6..0659ada92b5 100644
--- a/storage/spider/spd_direct_sql.cc
+++ b/storage/spider/spd_direct_sql.cc
@@ -371,6 +371,14 @@ SPIDER_CONN *spider_udf_direct_sql_create_conn(
if (direct_sql->access_mode == 0)
{
#endif
+ if (direct_sql->dbton_id == SPIDER_DBTON_SIZE)
+ {
+ /* Invalid target wrapper */
+ *error_num = ER_SPIDER_INVALID_CONNECT_INFO_NUM;
+ my_printf_error(*error_num, ER_SPIDER_INVALID_CONNECT_INFO_STR,
+ MYF(0), direct_sql->tgt_wrapper);
+ goto error_alloc_conn;
+ }
if (!(conn = (SPIDER_CONN *)
spider_bulk_malloc(spider_current_trx, 32, MYF(MY_WME | MY_ZEROFILL),
&conn, sizeof(*conn),
@@ -398,6 +406,14 @@ SPIDER_CONN *spider_udf_direct_sql_create_conn(
conn->default_database.init_calc_mem(138);
#if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET)
} else {
+ if (direct_sql->dbton_id == SPIDER_DBTON_SIZE)
+ {
+ /* Invalid target wrapper */
+ *error_num = ER_SPIDER_NOSQL_WRAPPER_IS_INVALID_NUM;
+ my_printf_error(*error_num, ER_SPIDER_NOSQL_WRAPPER_IS_INVALID_STR,
+ MYF(0), direct_sql->tgt_wrapper);
+ goto error_alloc_conn;
+ }
if (!(conn = (SPIDER_CONN *)
spider_bulk_malloc(spider_current_trx, 33, MYF(MY_WME | MY_ZEROFILL),
&conn, sizeof(*conn),
diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result b/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result
index 2e9faddbaff..3804a583dc3 100644
--- a/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result
+++ b/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result
@@ -10,7 +10,7 @@ col3 smallint(5) NOT NULL DEFAULT '1',
filler varchar(255) DEFAULT NULL,
KEY pk_ersatz(col1,col2,col3),
KEY key1 (col1,col2) USING BTREE
-) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA;
+) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1;
insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2;
insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2;
insert into t3 select 1410799999+a, 12345, 7890, 'data' from t2;
@@ -34,7 +34,7 @@ from t3
where col1 <= 1410799999
order by col1 desc,col2 desc,col3 desc limit 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL 2001 Using where; Using index
+1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL # Using where; Using index
# The same query but the constant is bigger.
# The query should use range(PRIMARY), not full index scan:
explain
@@ -43,5 +43,5 @@ from t3
where col1 <= 1412199999
order by col1 desc, col2 desc, col3 desc limit 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL 15001 Using where; Using index
+1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL # Using where; Using index
drop table t1,t2,t3;
diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test b/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test
index a809c3faf06..b723a5d72e8 100644
--- a/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test
+++ b/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test
@@ -15,7 +15,7 @@ CREATE TABLE t3 (
filler varchar(255) DEFAULT NULL,
KEY pk_ersatz(col1,col2,col3),
KEY key1 (col1,col2) USING BTREE
-) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA;
+) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1;
insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2;
insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2;
@@ -35,6 +35,7 @@ insert into t3 select 1412099999+a, 12345, 7890, 'data' from t2;
insert into t3 select 1412199999+a, 12345, 7890, 'data' from t2;
--echo # The following must use range(PRIMARY):
+--replace_column 9 #
explain
select col1,col2,col3
from t3
@@ -43,6 +44,7 @@ order by col1 desc,col2 desc,col3 desc limit 1;
--echo # The same query but the constant is bigger.
--echo # The query should use range(PRIMARY), not full index scan:
+--replace_column 9 #
explain
select col1,col2,col3
from t3
diff --git a/storage/xtradb/buf/buf0dump.cc b/storage/xtradb/buf/buf0dump.cc
index bf384390a98..1cc40fcfbad 100644
--- a/storage/xtradb/buf/buf0dump.cc
+++ b/storage/xtradb/buf/buf0dump.cc
@@ -216,7 +216,20 @@ buf_dump(
buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s",
full_filename);
- f = fopen(tmp_filename, "w");
+#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
+ f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
+#else
+ {
+ int fd;
+ fd = open(tmp_filename, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, 0640);
+ if (fd >= 0) {
+ f = fdopen(fd, "w");
+ }
+ else {
+ f = NULL;
+ }
+ }
+#endif
if (f == NULL) {
buf_dump_status(STATUS_ERR,
"Cannot open '%s' for writing: %s",
diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index b81ea60a413..97007c1107c 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -3685,6 +3685,117 @@ row_search_idx_cond_check(
return(result);
}
+/** Return the record field length in characters.
+@param[in] col table column of the field
+@param[in] field_no field number
+@param[in] rec physical record
+@param[in] offsets field offsets in the physical record
+@return field length in characters. */
+static
+size_t
+rec_field_len_in_chars(
+ const dict_col_t* col,
+ const ulint field_no,
+ const rec_t* rec,
+ const ulint* offsets)
+{
+ const ulint cset = dtype_get_charset_coll(col->prtype);
+ const CHARSET_INFO* cs = all_charsets[cset];
+ ulint rec_field_len;
+ const char* rec_field = reinterpret_cast<const char *>(
+ rec_get_nth_field(
+ rec, offsets, field_no, &rec_field_len));
+
+ if (UNIV_UNLIKELY(!cs)) {
+ ib_logf(IB_LOG_LEVEL_WARN, "Missing collation " ULINTPF, cset);
+ return SIZE_T_MAX;
+ }
+
+ return(cs->cset->numchars(cs, rec_field, rec_field + rec_field_len));
+}
+
+
+/** Avoid the clustered index lookup if all the following conditions
+are true:
+1) all columns are in secondary index
+2) all values for columns that are prefix-only indexes are shorter
+than the prefix size. This optimization can avoid many IOs for certain schemas.
+@return true, to avoid clustered index lookup. */
+static
+bool row_search_with_covering_prefix(
+ row_prebuilt_t* prebuilt,
+ const rec_t* rec,
+ const ulint* offsets)
+{
+ const dict_index_t* index = prebuilt->index;
+ ut_ad(!dict_index_is_clust(index));
+
+ if (!srv_prefix_index_cluster_optimization) {
+ return false;
+ }
+
+ /** Optimization only applicable if the number of secondary index
+ fields are greater than or equal to number of clustered index fields. */
+ if (prebuilt->n_template > index->n_fields) {
+ return false;
+ }
+
+ for (ulint i = 0; i < prebuilt->n_template; i++) {
+ mysql_row_templ_t* templ = prebuilt->mysql_template + i;
+ ulint j = templ->rec_prefix_field_no;
+
+ /** Condition (1) : is the field in the index. */
+ if (j == ULINT_UNDEFINED) {
+ return false;
+ }
+
+ /** Condition (2): If this is a prefix index then
+ row's value size shorter than prefix length. */
+
+ if (!templ->rec_field_is_prefix) {
+ continue;
+ }
+
+ ulint rec_size = rec_offs_nth_size(offsets, j);
+ const dict_field_t* field = dict_index_get_nth_field(index, j);
+ ulint max_chars = field->prefix_len / templ->mbmaxlen;
+
+ ut_a(field->prefix_len > 0);
+
+ if (rec_size < max_chars) {
+ /* Record in bytes shorter than the index
+ prefix length in char. */
+ continue;
+ }
+
+ if (rec_size * templ->mbminlen >= field->prefix_len) {
+ /* Shortest representation string by the
+ byte length of the record is longer than the
+ maximum possible index prefix. */
+ return false;
+ }
+
+
+ size_t num_chars = rec_field_len_in_chars(
+ field->col, j, rec, offsets);
+
+ if (num_chars >= max_chars) {
+ /* No of chars to store the record exceeds
+ the index prefix character length. */
+ return false;
+ }
+ }
+
+ for (ulint i = 0; i < prebuilt->n_template; i++) {
+ mysql_row_templ_t* templ = prebuilt->mysql_template + i;
+ templ->rec_field_no = templ->rec_prefix_field_no;
+ ut_a(templ->rec_field_no != ULINT_UNDEFINED);
+ }
+
+ srv_stats.n_sec_rec_cluster_reads_avoided.inc();
+ return true;
+}
+
/********************************************************************//**
Searches for rows in the database. This is used in the interface to
MySQL. This function opens a cursor, and also implements fetch next
@@ -3748,7 +3859,6 @@ row_search_for_mysql(
ulint* offsets = offsets_;
ibool table_lock_waited = FALSE;
byte* next_buf = 0;
- bool use_clustered_index = false;
rec_offs_init(offsets_);
@@ -4810,71 +4920,10 @@ locks_ok:
break;
}
- /* Get the clustered index record if needed, if we did not do the
- search using the clustered index... */
-
- use_clustered_index =
- (index != clust_index && prebuilt->need_to_access_clustered);
-
- if (use_clustered_index && srv_prefix_index_cluster_optimization
- && prebuilt->n_template <= index->n_fields) {
- /* ...but, perhaps avoid the clustered index lookup if
- all of the following are true:
- 1) all columns are in the secondary index
- 2) all values for columns that are prefix-only
- indexes are shorter than the prefix size
- This optimization can avoid many IOs for certain schemas.
- */
- bool row_contains_all_values = true;
- unsigned int i;
- for (i = 0; i < prebuilt->n_template; i++) {
- /* Condition (1) from above: is the field in the
- index (prefix or not)? */
- const mysql_row_templ_t* templ =
- prebuilt->mysql_template + i;
- ulint secondary_index_field_no =
- templ->rec_prefix_field_no;
- if (secondary_index_field_no == ULINT_UNDEFINED) {
- row_contains_all_values = false;
- break;
- }
- /* Condition (2) from above: if this is a
- prefix, is this row's value size shorter
- than the prefix? */
- if (templ->rec_field_is_prefix) {
- ulint record_size = rec_offs_nth_size(
- offsets,
- secondary_index_field_no);
- const dict_field_t *field =
- dict_index_get_nth_field(
- index,
- secondary_index_field_no);
- ut_a(field->prefix_len > 0);
- if (record_size >= field->prefix_len
- / templ->mbmaxlen) {
- row_contains_all_values = false;
- break;
- }
- }
- }
- /* If (1) and (2) were true for all columns above, use
- rec_prefix_field_no instead of rec_field_no, and skip
- the clustered lookup below. */
- if (row_contains_all_values) {
- for (i = 0; i < prebuilt->n_template; i++) {
- mysql_row_templ_t* templ =
- prebuilt->mysql_template + i;
- templ->rec_field_no =
- templ->rec_prefix_field_no;
- ut_a(templ->rec_field_no != ULINT_UNDEFINED);
- }
- use_clustered_index = false;
- srv_stats.n_sec_rec_cluster_reads_avoided.inc();
+ if (index != clust_index && prebuilt->need_to_access_clustered) {
+ if (row_search_with_covering_prefix(prebuilt, rec, offsets)) {
+ goto use_covering_index;
}
- }
-
- if (use_clustered_index) {
-
requires_clust_rec:
ut_ad(index != clust_index);
/* We use a 'goto' to the preceding label if a consistent
@@ -4960,6 +5009,7 @@ requires_clust_rec:
}
}
} else {
+use_covering_index:
result_rec = rec;
}