Commit 4d51ca63 authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.1 into 10.2

This also fixes MDEV-20464.
parents ebafe5a2 94e9dc95
[covering]
innodb_prefix_index_cluster_optimization=on
[unoptimized]
innodb_prefix_index_cluster_optimization=off
drop table if exists prefixinno;
SET @save_opt= @@GLOBAL.innodb_prefix_index_cluster_optimization;
set global innodb_prefix_index_cluster_optimization = ON;
show variables like 'innodb_prefix_index_cluster_optimization';
Variable_name Value
......@@ -346,10 +346,10 @@ f1
🐱🌑
select @cluster_lookups;
@cluster_lookups
2
1
select @cluster_lookups_avoided;
@cluster_lookups_avoided
0
1
# Eligible - record length is shorter than prefix length
SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌑%';
f1
......@@ -366,10 +366,10 @@ f1
🌒
select @cluster_lookups;
@cluster_lookups
1
0
select @cluster_lookups_avoided;
@cluster_lookups_avoided
1
2
DROP TABLE t1;
CREATE TABLE t1(
col1 INT,
......@@ -398,4 +398,60 @@ select @cluster_lookups_avoided;
@cluster_lookups_avoided
0
DROP TABLE t1;
set global innodb_prefix_index_cluster_optimization = OFF;
#
# MDEV-20464 Division by 0 in row_search_with_covering_prefix()
#
CREATE TABLE t1 (f1 INT, f2 INT AS (f1), f3 INT AS (f1), f4 INT AS (f1),
KEY (f1,f2,f3)) ENGINE=InnoDB;
INSERT INTO t1 (f1) VALUES (NULL),(0);
SELECT f1, MAX(f3), COUNT(f4) FROM t1 GROUP BY f1;
f1 MAX(f3) COUNT(f4)
NULL NULL 0
0 0 1
DROP TABLE t1;
#
# MDEV-23600 Division by 0 in row_search_with_covering_prefix()
#
CREATE TABLE t(c POINT UNIQUE) ENGINE=InnoDB;
INSERT t SET c=POINT(1,1);
SELECT * FROM t WHERE c > (SELECT MAX(c) FROM t);
c
DROP TABLE t;
#
# MDEV-12486 Wrong results with innodb_prefix_index_cluster_optimization
#
CREATE TABLE wp_blogs (
blog_id bigint(20) NOT NULL auto_increment,
site_id bigint(20) NOT NULL default '0',
domain varchar(200) NOT NULL default '',
path varchar(100) NOT NULL default '',
registered datetime NOT NULL default '0000-00-00 00:00:00',
last_updated datetime NOT NULL default '0000-00-00 00:00:00',
public tinyint(2) NOT NULL default '1',
archived tinyint(2) NOT NULL default '0',
mature tinyint(2) NOT NULL default '0',
spam tinyint(2) NOT NULL default '0',
deleted tinyint(2) NOT NULL default '0',
lang_id int(11) NOT NULL default '0',
PRIMARY KEY (blog_id),
KEY domain (domain(50),path(5)),
KEY lang_id (lang_id)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
INSERT INTO wp_blogs (domain, path) VALUES
('domain.no', '/fondsinvesteringer/'), ('domain.no', '/'),
('foo', 'bar'), ('bar', 'foo'), ('foo', 'foo'), ('bar', 'bar'),
('foo', 'foobar'), ('bar', 'foobar'), ('foobar', 'foobar');
SET GLOBAL innodb_prefix_index_cluster_optimization=off;
SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no')
AND path IN ( '/fondsinvesteringer/', '/' );
blog_id
2
1
SET GLOBAL innodb_prefix_index_cluster_optimization=on;
SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no')
AND path IN ( '/fondsinvesteringer/', '/' );
blog_id
2
1
DROP TABLE wp_blogs;
SET GLOBAL innodb_prefix_index_cluster_optimization = @save_opt;
This diff is collapsed.
This diff is collapsed.
......@@ -3356,6 +3356,22 @@ SET sort_buffer_size= @save_sort_buffer_size;
SET max_length_for_sort_data= @save_max_length_for_sort_data;
DROP TABLE t1;
#
# MDEV-23596: Assertion `tab->ref.use_count' failed in join_read_key_unlock_row
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, KEY(b));
INSERT INTO t1 VALUES (0, 1),(1, 2);
CREATE TABLE t2 SELECT * FROM t1;
EXPLAIN SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
2 DEPENDENT SUBQUERY t1 index PRIMARY b 5 NULL 1 Using where
SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2;
c
1
NULL
DROP TABLE t1,t2;
# end of 10.1 tests
#
# MDEV-13994: Bad join results with orderby_uses_equalities=on
#
CREATE TABLE books (
......
create table d1 (a int);
create temporary table t1 (a int);
create temporary table t2 (a int);
Got one of the listed errors
create temporary table t3 (a int) engine=Aria;
Got one of the listed errors
select * from information_schema.columns where table_schema='test';
Got one of the listed errors
flush tables;
select * from d1;
a
drop temporary table t1;
drop table d1;
-- source include/have_innodb.inc
--disable_warnings
drop table if exists prefixinno;
--enable_warnings
SET @save_opt= @@GLOBAL.innodb_prefix_index_cluster_optimization;
set global innodb_prefix_index_cluster_optimization = ON;
show variables like 'innodb_prefix_index_cluster_optimization';
......@@ -665,4 +662,58 @@ select @cluster_lookups;
select @cluster_lookups_avoided;
DROP TABLE t1;
set global innodb_prefix_index_cluster_optimization = OFF;
--echo #
--echo # MDEV-20464 Division by 0 in row_search_with_covering_prefix()
--echo #
CREATE TABLE t1 (f1 INT, f2 INT AS (f1), f3 INT AS (f1), f4 INT AS (f1),
KEY (f1,f2,f3)) ENGINE=InnoDB;
INSERT INTO t1 (f1) VALUES (NULL),(0);
SELECT f1, MAX(f3), COUNT(f4) FROM t1 GROUP BY f1;
DROP TABLE t1;
--echo #
--echo # MDEV-23600 Division by 0 in row_search_with_covering_prefix()
--echo #
CREATE TABLE t(c POINT UNIQUE) ENGINE=InnoDB;
INSERT t SET c=POINT(1,1);
SELECT * FROM t WHERE c > (SELECT MAX(c) FROM t);
DROP TABLE t;
--echo #
--echo # MDEV-12486 Wrong results with innodb_prefix_index_cluster_optimization
--echo #
CREATE TABLE wp_blogs (
blog_id bigint(20) NOT NULL auto_increment,
site_id bigint(20) NOT NULL default '0',
domain varchar(200) NOT NULL default '',
path varchar(100) NOT NULL default '',
registered datetime NOT NULL default '0000-00-00 00:00:00',
last_updated datetime NOT NULL default '0000-00-00 00:00:00',
public tinyint(2) NOT NULL default '1',
archived tinyint(2) NOT NULL default '0',
mature tinyint(2) NOT NULL default '0',
spam tinyint(2) NOT NULL default '0',
deleted tinyint(2) NOT NULL default '0',
lang_id int(11) NOT NULL default '0',
PRIMARY KEY (blog_id),
KEY domain (domain(50),path(5)),
KEY lang_id (lang_id)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
INSERT INTO wp_blogs (domain, path) VALUES
('domain.no', '/fondsinvesteringer/'), ('domain.no', '/'),
('foo', 'bar'), ('bar', 'foo'), ('foo', 'foo'), ('bar', 'bar'),
('foo', 'foobar'), ('bar', 'foobar'), ('foobar', 'foobar');
SET GLOBAL innodb_prefix_index_cluster_optimization=off;
SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no')
AND path IN ( '/fondsinvesteringer/', '/' );
SET GLOBAL innodb_prefix_index_cluster_optimization=on;
SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no')
AND path IN ( '/fondsinvesteringer/', '/' );
DROP TABLE wp_blogs;
SET GLOBAL innodb_prefix_index_cluster_optimization = @save_opt;
[on]
optimizer_switch=extended_keys=on
[off]
optimizer_switch=extended_keys=off
This diff is collapsed.
......@@ -2200,6 +2200,21 @@ SET sort_buffer_size= @save_sort_buffer_size;
SET max_length_for_sort_data= @save_max_length_for_sort_data;
DROP TABLE t1;
--echo #
--echo # MDEV-23596: Assertion `tab->ref.use_count' failed in join_read_key_unlock_row
--echo #
CREATE TABLE t1 (a INT PRIMARY KEY, b INT, KEY(b));
INSERT INTO t1 VALUES (0, 1),(1, 2);
CREATE TABLE t2 SELECT * FROM t1;
EXPLAIN SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2;
SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2;
DROP TABLE t1,t2;
--echo # end of 10.1 tests
--echo #
--echo # MDEV-13994: Bad join results with orderby_uses_equalities=on
--echo #
......
source include/not_windows.inc;
#
# MDEV-23569 temporary tables can overwrite existing files
#
let datadir=`select @@datadir`;
create table d1 (a int);
create temporary table t1 (a int);
perl;
chdir "$ENV{MYSQL_TMP_DIR}/mysqld.1/";
for (<#sql*.MYI>) {
/^#sql(.*)_([0-9a-f]+_)([0-9a-f]+)\.MYI$/ or die;
symlink "$ENV{datadir}/test/d1.MYI", sprintf "#sql$1_$2%x.MYI", hex($3)+1;
symlink "$ENV{datadir}/test/d1.MYI", sprintf "#sql$1_$2%x.MAI", hex($3)+1;
symlink "$ENV{datadir}/test/d1.MYI", sprintf "#sql$1_$2%x.MAI", hex($3)+2;
symlink "$ENV{datadir}/test/d1.MYI", "#sql_$1_0.MAI";
}
EOF
error 1,1030;
create temporary table t2 (a int);
error 1,1030;
create temporary table t3 (a int) engine=Aria;
error 1,1030;
select * from information_schema.columns where table_schema='test';
flush tables;
select * from d1;
drop temporary table t1;
remove_files_wildcard $MYSQL_TMP_DIR/mysqld.1 *sql*;
drop table d1;
......@@ -21924,6 +21924,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
else if (select && select->quick)
select->quick->need_sorted_output();
tab->read_record.unlock_row= (tab->type == JT_EQ_REF) ?
join_read_key_unlock_row : rr_unlock_row;
} // QEP has been modified
/*
......
......@@ -4169,6 +4169,10 @@ bool row_search_with_covering_prefix(
const dict_index_t* index = prebuilt->index;
ut_ad(!dict_index_is_clust(index));
if (dict_index_is_spatial(index)) {
return false;
}
if (!srv_prefix_index_cluster_optimization) {
return false;
}
......@@ -4179,9 +4183,16 @@ bool row_search_with_covering_prefix(
return false;
}
/* We can avoid a clustered index lookup if
all of the following hold:
(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. */
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;
ut_ad(!templ->mbminlen == !templ->mbmaxlen);
/** Condition (1) : is the field in the index. */
if (j == ULINT_UNDEFINED) {
......@@ -4191,33 +4202,29 @@ bool row_search_with_covering_prefix(
/** Condition (2): If this is a prefix index then
row's value size shorter than prefix length. */
if (!templ->rec_field_is_prefix) {
if (!templ->rec_field_is_prefix
|| rec_offs_nth_sql_null(offsets, j)) {
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. */
if (!field->prefix_len) {
continue;
}
if (rec_size * templ->mbminlen >= field->prefix_len) {
const ulint rec_size = rec_offs_nth_size(offsets, j);
if (rec_size >= 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) {
if (templ->mbminlen != templ->mbmaxlen
&& rec_field_len_in_chars(field->col, j, rec, offsets)
>= field->prefix_len / templ->mbmaxlen) {
/* No of chars to store the record exceeds
the index prefix character length. */
return false;
......
......@@ -318,7 +318,7 @@ int maria_create(const char *name, enum data_file_type datafile_type,
{
options|= HA_OPTION_TMP_TABLE;
tmp_table= TRUE;
create_mode|= O_NOFOLLOW;
create_mode|= O_NOFOLLOW | (internal_table ? 0 : O_EXCL);
/* "CREATE TEMPORARY" tables are not crash-safe (dropped at restart) */
ci->transactional= FALSE;
flags&= ~HA_CREATE_PAGE_CHECKSUM;
......@@ -886,8 +886,8 @@ int maria_create(const char *name, enum data_file_type datafile_type,
{
char *iext= strrchr(name, '.');
int have_iext= iext && !strcmp(iext, MARIA_NAME_IEXT);
fn_format(kfilename, name, "", MARIA_NAME_IEXT,
MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
fn_format(kfilename, name, "", MARIA_NAME_IEXT, MY_UNPACK_FILENAME |
(internal_table ? 0 : MY_RETURN_REAL_PATH) |
(have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
/*
Replace the current file.
......
......@@ -184,7 +184,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (flags & HA_CREATE_TMP_TABLE)
{
options|= HA_OPTION_TMP_TABLE;
create_mode|= O_NOFOLLOW;
create_mode|= O_NOFOLLOW | (internal_table ? 0 : O_EXCL);
}
if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
{
......@@ -619,8 +619,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
{
char *iext= strrchr(name, '.');
int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
fn_format(kfilename, name, "", MI_NAME_IEXT,
MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
fn_format(kfilename, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME |
(internal_table ? 0 : MY_RETURN_REAL_PATH) |
(have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
/* Replace the current file */
create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
......
......@@ -2,7 +2,7 @@
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2015, 2018, MariaDB Corporation.
Copyright (c) 2015, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
......@@ -3740,9 +3740,16 @@ bool row_search_with_covering_prefix(
return false;
}
/* We can avoid a clustered index lookup if
all of the following hold:
(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. */
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;
ut_ad(!templ->mbminlen == !templ->mbmaxlen);
/** Condition (1) : is the field in the index. */
if (j == ULINT_UNDEFINED) {
......@@ -3752,34 +3759,29 @@ bool row_search_with_covering_prefix(
/** Condition (2): If this is a prefix index then
row's value size shorter than prefix length. */
if (!templ->rec_field_is_prefix) {
if (!templ->rec_field_is_prefix
|| rec_offs_nth_sql_null(offsets, j)) {
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. */
if (!field->prefix_len) {
continue;
}
if (rec_size * templ->mbminlen >= field->prefix_len) {
const ulint rec_size = rec_offs_nth_size(offsets, j);
if (rec_size >= 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) {
if (templ->mbminlen != templ->mbmaxlen
&& rec_field_len_in_chars(field->col, j, rec, offsets)
>= field->prefix_len / templ->mbmaxlen) {
/* No of chars to store the record exceeds
the index prefix character length. */
return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment