1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-09 22:24:09 +03:00

Merge branch '10.2' of github.com:MariaDB/server into bb-10.2-mariarocks

This commit is contained in:
Sergei Petrunia
2017-04-04 17:12:06 +03:00
17 changed files with 1965 additions and 151 deletions

3
.gitignore vendored
View File

@@ -97,6 +97,9 @@ pcre/pcre_chartables.c
pcre/pcregrep pcre/pcregrep
pcre/pcretest pcre/pcretest
pcre/test*grep pcre/test*grep
plugin/aws_key_management/aws-sdk-cpp
plugin/aws_key_management/aws_sdk_cpp
plugin/aws_key_management/aws_sdk_cpp-prefix
scripts/comp_sql scripts/comp_sql
scripts/make_binary_distribution scripts/make_binary_distribution
scripts/msql2mysql scripts/msql2mysql

View File

@@ -2332,3 +2332,677 @@ DROP TABLE t1;
# #
# End of 10.1 tests # End of 10.1 tests
# #
#
# MDEV-10454: range access keys extracted
# from <row> IN (<row value list>)
#
create table t1(a int, b int, c varchar(16), key idx(a,b)) engine=myisam;
insert into t1 values
(1,1,'xx'), (2,2,'yyy'), (3,3,'zzzz'), (1,2,'zz'), (1,3,'x'),
(2,3,'yy'), (4,5,'ww'), (7,8,'xxxxx'), (4,3,'zyx'), (1,2,'uuu'),
(2,1,'w'), (5,5,'wx'), (2,3,'ww'), (7,7,'xxxyy'), (3,3,'zyxw'),
(3,2,'uuuw'), (2,2,'wxz'), (5,5,'xw'), (12,12,'xx'), (12,12,'y'),
(13,13,'z'), (11,12,'zz'), (11,13,'x'), (12,13,'y'), (14,15,'w'),
(17,18,'xx'), (14,13,'zx'), (11,12,'u'), (12,11,'w'), (5,5,'wx'),
(12,13,'ww'), (17,17,'xxxyy'), (13,13,'zyxw'), (13,12,'uuuw'), (12,12,'wxz'),
(15,15,'xw'), (1,1,'xa'), (2,2,'yya'), (3,3,'zzza'), (1,2,'za'),
(1,3,'xb'), (2,3,'ya'), (4,5,'wa'), (7,8,'xxxxa'), (4,3,'zya'),
(1,2,'uua'), (2,1,'wb'), (5,5,'wc'), (2,3,'wa'), (7,7,'xxxya'),
(3,3,'zyxa'), (3,2,'uuua'), (2,2,'wxa'), (5,5,'xa'), (12,12,'xa'),
(22,12,'yb'), (23,13,'zb'), (21,12,'za'), (24,13,'c'), (32,13,'d'),
(34,15,'wd'), (47,18,'xa'), (54,13,'za'), (51,12,'ub'), (52,11,'wc'),
(5,5,'wd'), (62,13,'wa'), (67,17,'xxxya'), (63,13,'zyxa'), (73,12,'uuua'),
(82,12,'wxa'), (85,15,'xd');
# range access to t1 by 2-component keys for index idx
explain select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 10 NULL 7 Using where
explain format=json select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "10",
"used_key_parts": ["a", "b"],
"rows": 7,
"filtered": 100,
"attached_condition": "(t1.a,t1.b) in (<cache>((2,3)),<cache>((3,3)),<cache>((8,8)),<cache>((7,7)))"
}
}
}
select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7));
a b c
2 3 yy
2 3 ww
2 3 ya
2 3 wa
3 3 zzzz
3 3 zyxw
3 3 zzza
3 3 zyxa
7 7 xxxyy
7 7 xxxya
prepare stmt from "select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7))";
execute stmt;
a b c
2 3 yy
2 3 ww
2 3 ya
2 3 wa
3 3 zzzz
3 3 zyxw
3 3 zzza
3 3 zyxa
7 7 xxxyy
7 7 xxxya
execute stmt;
a b c
2 3 yy
2 3 ww
2 3 ya
2 3 wa
3 3 zzzz
3 3 zyxw
3 3 zzza
3 3 zyxa
7 7 xxxyy
7 7 xxxya
deallocate prepare stmt;
# range access to t1 by 1-component keys for index idx
explain select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 5 Using where
explain format=json select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 5,
"filtered": 100,
"attached_condition": "(t1.a,t1.b + t1.a) in (<cache>((4,9)),<cache>((8,8)),<cache>((7,7)))"
}
}
}
select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7));
a b c
4 5 ww
4 5 wa
# range access to t1 by 1-component keys for index idx
explain select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 5 Using where
explain format=json select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 5,
"filtered": 100,
"attached_condition": "(t1.a,t1.b) in ((4,t1.a - 1),(8,t1.a + 8),(7,t1.a + 7))"
}
}
}
select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7));
a b c
4 3 zyx
4 3 zya
set @save_optimizer_switch=@@optimizer_switch;
set optimizer_switch='index_merge=off';
create table t2(
d int, e int, key idx1(d), key idx2(e), f varchar(32)
) engine=myisam;
insert into t2 values
(9,5,'a'), (9,8,'b'), (9,3,'c'), (9,2,'d'), (9,1,'e'),
(6,5,'f'), (6,3,'g'), (6,7,'h'), (3,3,'i'), (6,2,'j'),
(9,5,'aa'), (9,8,'ba'), (9,3,'ca'), (2,2,'da'), (9,1,'ea'),
(6,5,'fa'), (6,3,'ga'), (6,7,'ha'), (9,3,'ia'), (6,2,'ja');
# join order: (t2,t1) with ref access of t1
# range access to t1 by keys for index idx1
explain select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(2,2));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range idx1,idx2 idx1 5 NULL 3 Using index condition; Using where
1 SIMPLE t1 ref idx idx 5 test.t2.d 8
explain format=json select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(2,2));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "5",
"used_key_parts": ["d"],
"rows": 3,
"filtered": 100,
"index_condition": "t2.d is not null",
"attached_condition": "(t2.d,t2.e) in (<cache>((3,3)),<cache>((7,7)),<cache>((2,2)))"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.d"],
"rows": 8,
"filtered": 100
}
}
}
select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(2,2));
a b c d e f
2 1 w 2 2 da
2 1 wb 2 2 da
2 2 yyy 2 2 da
2 2 wxz 2 2 da
2 2 yya 2 2 da
2 2 wxa 2 2 da
2 3 yy 2 2 da
2 3 ww 2 2 da
2 3 ya 2 2 da
2 3 wa 2 2 da
3 2 uuuw 3 3 i
3 2 uuua 3 3 i
3 3 zzzz 3 3 i
3 3 zyxw 3 3 i
3 3 zzza 3 3 i
3 3 zyxa 3 3 i
insert into t2 values
(4,5,'a'), (7,8,'b'), (4,3,'c'), (1,2,'d'), (2,1,'e'), (5,5,'f'),
(2,3,'g'), (7,7,'h'), (3,3,'i'), (3,2,'j'), (2,2,'k'), (5,5,'l'),
(4,5,'aa'), (7,8,'bb'), (4,3,'cc'), (1,2,'dd'), (2,1,'ee'), (9,5,'ff'),
(2,3,'gg'), (7,7,'hh'), (3,3,'ii'), (3,2,'jj'), (2,2,'kk'), (9,5,'ll'),
(4,5,'aaa'), (7,8,'bbb'), (4,3,'ccc'), (1,2,'ddd'), (2,1,'eee'), (5,5,'fff'),
(2,3,'ggg'), (7,7,'hhh'), (3,3,'iii'), (3,2,'jjj'), (2,2,'kkk'), (5,5,'lll'),
(14,15,'a'), (17,18,'b'), (14,13,'c'), (11,12,'d'), (12,11,'e'), (15,15,'f'),
(12,13,'g'), (17,17,'h'), (13,13,'i'), (13,12,'j'), (12,12,'k'), (15,15,'l'),
(24,25,'a'), (27,28,'b'), (24,23,'c'), (21,22,'d'), (22,21,'e'), (25,25,'f'),
(22,23,'g'), (27,27,'h'), (23,23,'i'), (23,22,'j'), (22,22,'k'), (25,25,'l'),
(34,35,'a'), (37,38,'b'), (34,33,'c'), (31,32,'d'), (32,31,'e'), (35,35,'f'),
(32,33,'g'), (37,37,'h'), (33,33,'i'), (33,32,'j'), (32,32,'k'), (35,35,'l'),
(44,45,'a'), (47,48,'b'), (44,43,'c'), (41,42,'d'), (42,41,'e'), (45,45,'f'),
(42,43,'g'), (47,47,'h'), (43,43,'i'), (43,42,'j'), (42,42,'k'), (45,45,'l');
# join order: (t1,t2) with ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 6 Using index condition
1 SIMPLE t2 ref idx1,idx2 idx1 5 test.t1.a 12 Using where
explain format=json select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 6,
"filtered": 100,
"index_condition": "t1.a is not null"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 12,
"filtered": 100,
"attached_condition": "(t1.a,t2.e) in (<cache>((3,3)),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1;
a b c d e f
3 2 uuuw 3 3 i
3 2 uuuw 3 3 i
3 2 uuua 3 3 i
3 2 uuua 3 3 i
3 3 zzzz 3 3 i
3 3 zzzz 3 3 i
3 3 zyxw 3 3 i
3 3 zyxw 3 3 i
3 3 zzza 3 3 i
3 3 zzza 3 3 i
3 3 zyxa 3 3 i
3 3 zyxa 3 3 i
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
prepare stmt from "select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1";
execute stmt;
a b c d e f
3 2 uuuw 3 3 i
3 2 uuuw 3 3 i
3 2 uuua 3 3 i
3 2 uuua 3 3 i
3 3 zzzz 3 3 i
3 3 zzzz 3 3 i
3 3 zyxw 3 3 i
3 3 zyxw 3 3 i
3 3 zzza 3 3 i
3 3 zzza 3 3 i
3 3 zyxa 3 3 i
3 3 zyxa 3 3 i
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
execute stmt;
a b c d e f
3 2 uuuw 3 3 i
3 2 uuuw 3 3 i
3 2 uuua 3 3 i
3 2 uuua 3 3 i
3 3 zzzz 3 3 i
3 3 zzzz 3 3 i
3 3 zyxw 3 3 i
3 3 zyxw 3 3 i
3 3 zzza 3 3 i
3 3 zzza 3 3 i
3 3 zyxa 3 3 i
3 3 zyxa 3 3 i
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
deallocate prepare stmt;
insert into t1 select * from t1;
# join order: (t2,t1) with ref access of t1
# range access to t2 by keys for index idx2
explain select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range idx1,idx2 idx2 5 NULL 6 Using where
1 SIMPLE t1 ref idx idx 5 test.t2.d 11
explain format=json select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx2",
"key_length": "5",
"used_key_parts": ["e"],
"rows": 6,
"filtered": 100,
"attached_condition": "(t2.d,t2.e) in (<cache>((4,4)),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1 and t2.d is not null"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.d"],
"rows": 11,
"filtered": 100
}
}
}
select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
a b c d e f
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
alter table t2 drop index idx1, drop index idx2, add index idx3(d,e);
# join order: (t2,t1) with ref access of t1
# range access to t2 by 2-component keys for index idx3
explain select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range idx3 idx3 10 NULL 5 Using index condition; Using where
1 SIMPLE t1 ref idx idx 5 test.t2.d 11
explain format=json select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "10",
"used_key_parts": ["d", "e"],
"rows": 5,
"filtered": 100,
"index_condition": "t2.d is not null",
"attached_condition": "(t2.d,t2.e) in (<cache>((4,4)),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.d"],
"rows": 11,
"filtered": 100
}
}
}
select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
a b c d e f
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
# join order: (t1,t2) with ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2
where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 15 Using index condition
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2
where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 15,
"filtered": 100,
"index_condition": "t1.a is not null"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1;
a b c d e f
4 3 zyx 4 5 a
4 3 zya 4 5 a
4 3 zyx 4 5 a
4 3 zya 4 5 a
4 5 ww 4 5 a
4 5 wa 4 5 a
4 5 ww 4 5 a
4 5 wa 4 5 a
7 7 xxxyy 7 8 b
7 7 xxxya 7 8 b
7 7 xxxyy 7 8 b
7 7 xxxya 7 8 b
7 8 xxxxx 7 8 b
7 8 xxxxa 7 8 b
7 8 xxxxx 7 8 b
7 8 xxxxa 7 8 b
# join order: (t1,t2) with ref access of t2
# no range access
explain select * from t1,t2
where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL idx NULL NULL NULL 144 Using where
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2
where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"possible_keys": ["idx"],
"rows": 144,
"filtered": 100,
"attached_condition": "t1.a is not null"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1;
a b c d e f
7 8 xxxxx 7 7 h
7 7 xxxyy 7 7 h
7 8 xxxxa 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 7 xxxyy 7 7 h
7 8 xxxxa 7 7 h
7 7 xxxya 7 7 h
# join order: (t1,t2) with ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 13,
"filtered": 100,
"index_condition": "t1.a is not null",
"attached_condition": "(t1.a,2) in (<cache>((2,2)),<cache>((7,7)),<cache>((8,8))) and length(t1.c) = 1"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
a b c d e f
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
prepare stmt from "select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1";
execute stmt;
a b c d e f
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
execute stmt;
a b c d e f
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
deallocate prepare stmt;
create table t3 (id int primary key, v int) engine=myisam;
insert into t3 values
(3,2), (1,1), (4,12), (2,15);
# join order: (t3,t1,t2) with const t3 and ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t3",
"access_type": "const",
"possible_keys": ["PRIMARY"],
"key": "PRIMARY",
"key_length": "4",
"used_key_parts": ["id"],
"ref": ["const"],
"rows": 1,
"filtered": 100
},
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 13,
"filtered": 100,
"index_condition": "t1.a is not null",
"attached_condition": "(t1.a,1 + 1) in (<cache>((2,2)),<cache>((7,7)),<cache>((8,8))) and length(t1.c) = 1"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "length(t2.f) = 1"
}
}
}
select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
a b c d e f id v
2 1 w 2 1 e 1 1
2 1 w 2 2 k 1 1
2 1 w 2 3 g 1 1
2 1 w 2 1 e 1 1
2 1 w 2 2 k 1 1
2 1 w 2 3 g 1 1
# IN predicate is always FALSE
explain select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((9,9),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
prepare stmt from "select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((9,9),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1";
execute stmt;
a b c d e f id v
execute stmt;
a b c d e f id v
deallocate prepare stmt;
set optimizer_switch=@save_optimizer_switch;
drop table t1,t2,t3;
#
# End of 10.2 tests
#

View File

@@ -2334,4 +2334,688 @@ DROP TABLE t1;
# #
# End of 10.1 tests # End of 10.1 tests
# #
#
# MDEV-10454: range access keys extracted
# from <row> IN (<row value list>)
#
create table t1(a int, b int, c varchar(16), key idx(a,b)) engine=myisam;
insert into t1 values
(1,1,'xx'), (2,2,'yyy'), (3,3,'zzzz'), (1,2,'zz'), (1,3,'x'),
(2,3,'yy'), (4,5,'ww'), (7,8,'xxxxx'), (4,3,'zyx'), (1,2,'uuu'),
(2,1,'w'), (5,5,'wx'), (2,3,'ww'), (7,7,'xxxyy'), (3,3,'zyxw'),
(3,2,'uuuw'), (2,2,'wxz'), (5,5,'xw'), (12,12,'xx'), (12,12,'y'),
(13,13,'z'), (11,12,'zz'), (11,13,'x'), (12,13,'y'), (14,15,'w'),
(17,18,'xx'), (14,13,'zx'), (11,12,'u'), (12,11,'w'), (5,5,'wx'),
(12,13,'ww'), (17,17,'xxxyy'), (13,13,'zyxw'), (13,12,'uuuw'), (12,12,'wxz'),
(15,15,'xw'), (1,1,'xa'), (2,2,'yya'), (3,3,'zzza'), (1,2,'za'),
(1,3,'xb'), (2,3,'ya'), (4,5,'wa'), (7,8,'xxxxa'), (4,3,'zya'),
(1,2,'uua'), (2,1,'wb'), (5,5,'wc'), (2,3,'wa'), (7,7,'xxxya'),
(3,3,'zyxa'), (3,2,'uuua'), (2,2,'wxa'), (5,5,'xa'), (12,12,'xa'),
(22,12,'yb'), (23,13,'zb'), (21,12,'za'), (24,13,'c'), (32,13,'d'),
(34,15,'wd'), (47,18,'xa'), (54,13,'za'), (51,12,'ub'), (52,11,'wc'),
(5,5,'wd'), (62,13,'wa'), (67,17,'xxxya'), (63,13,'zyxa'), (73,12,'uuua'),
(82,12,'wxa'), (85,15,'xd');
# range access to t1 by 2-component keys for index idx
explain select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 10 NULL 7 Using where; Rowid-ordered scan
explain format=json select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "10",
"used_key_parts": ["a", "b"],
"rows": 7,
"filtered": 100,
"attached_condition": "(t1.a,t1.b) in (<cache>((2,3)),<cache>((3,3)),<cache>((8,8)),<cache>((7,7)))",
"mrr_type": "Rowid-ordered scan"
}
}
}
select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7));
a b c
3 3 zzzz
2 3 yy
2 3 ww
7 7 xxxyy
3 3 zyxw
3 3 zzza
2 3 ya
2 3 wa
7 7 xxxya
3 3 zyxa
prepare stmt from "select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7))";
execute stmt;
a b c
3 3 zzzz
2 3 yy
2 3 ww
7 7 xxxyy
3 3 zyxw
3 3 zzza
2 3 ya
2 3 wa
7 7 xxxya
3 3 zyxa
execute stmt;
a b c
3 3 zzzz
2 3 yy
2 3 ww
7 7 xxxyy
3 3 zyxw
3 3 zzza
2 3 ya
2 3 wa
7 7 xxxya
3 3 zyxa
deallocate prepare stmt;
# range access to t1 by 1-component keys for index idx
explain select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 5 Using where; Rowid-ordered scan
explain format=json select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 5,
"filtered": 100,
"attached_condition": "(t1.a,t1.b + t1.a) in (<cache>((4,9)),<cache>((8,8)),<cache>((7,7)))",
"mrr_type": "Rowid-ordered scan"
}
}
}
select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7));
a b c
4 5 ww
4 5 wa
# range access to t1 by 1-component keys for index idx
explain select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 5 Using where; Rowid-ordered scan
explain format=json select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 5,
"filtered": 100,
"attached_condition": "(t1.a,t1.b) in ((4,t1.a - 1),(8,t1.a + 8),(7,t1.a + 7))",
"mrr_type": "Rowid-ordered scan"
}
}
}
select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7));
a b c
4 3 zyx
4 3 zya
set @save_optimizer_switch=@@optimizer_switch;
set optimizer_switch='index_merge=off';
create table t2(
d int, e int, key idx1(d), key idx2(e), f varchar(32)
) engine=myisam;
insert into t2 values
(9,5,'a'), (9,8,'b'), (9,3,'c'), (9,2,'d'), (9,1,'e'),
(6,5,'f'), (6,3,'g'), (6,7,'h'), (3,3,'i'), (6,2,'j'),
(9,5,'aa'), (9,8,'ba'), (9,3,'ca'), (2,2,'da'), (9,1,'ea'),
(6,5,'fa'), (6,3,'ga'), (6,7,'ha'), (9,3,'ia'), (6,2,'ja');
# join order: (t2,t1) with ref access of t1
# range access to t1 by keys for index idx1
explain select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(2,2));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range idx1,idx2 idx1 5 NULL 3 Using index condition; Using where; Rowid-ordered scan
1 SIMPLE t1 ref idx idx 5 test.t2.d 8
explain format=json select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(2,2));
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "5",
"used_key_parts": ["d"],
"rows": 3,
"filtered": 100,
"index_condition": "t2.d is not null",
"attached_condition": "(t2.d,t2.e) in (<cache>((3,3)),<cache>((7,7)),<cache>((2,2)))",
"mrr_type": "Rowid-ordered scan"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.d"],
"rows": 8,
"filtered": 100
}
}
}
select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(2,2));
a b c d e f
3 2 uuuw 3 3 i
3 2 uuua 3 3 i
3 3 zzzz 3 3 i
3 3 zyxw 3 3 i
3 3 zzza 3 3 i
3 3 zyxa 3 3 i
2 1 w 2 2 da
2 1 wb 2 2 da
2 2 yyy 2 2 da
2 2 wxz 2 2 da
2 2 yya 2 2 da
2 2 wxa 2 2 da
2 3 yy 2 2 da
2 3 ww 2 2 da
2 3 ya 2 2 da
2 3 wa 2 2 da
insert into t2 values
(4,5,'a'), (7,8,'b'), (4,3,'c'), (1,2,'d'), (2,1,'e'), (5,5,'f'),
(2,3,'g'), (7,7,'h'), (3,3,'i'), (3,2,'j'), (2,2,'k'), (5,5,'l'),
(4,5,'aa'), (7,8,'bb'), (4,3,'cc'), (1,2,'dd'), (2,1,'ee'), (9,5,'ff'),
(2,3,'gg'), (7,7,'hh'), (3,3,'ii'), (3,2,'jj'), (2,2,'kk'), (9,5,'ll'),
(4,5,'aaa'), (7,8,'bbb'), (4,3,'ccc'), (1,2,'ddd'), (2,1,'eee'), (5,5,'fff'),
(2,3,'ggg'), (7,7,'hhh'), (3,3,'iii'), (3,2,'jjj'), (2,2,'kkk'), (5,5,'lll'),
(14,15,'a'), (17,18,'b'), (14,13,'c'), (11,12,'d'), (12,11,'e'), (15,15,'f'),
(12,13,'g'), (17,17,'h'), (13,13,'i'), (13,12,'j'), (12,12,'k'), (15,15,'l'),
(24,25,'a'), (27,28,'b'), (24,23,'c'), (21,22,'d'), (22,21,'e'), (25,25,'f'),
(22,23,'g'), (27,27,'h'), (23,23,'i'), (23,22,'j'), (22,22,'k'), (25,25,'l'),
(34,35,'a'), (37,38,'b'), (34,33,'c'), (31,32,'d'), (32,31,'e'), (35,35,'f'),
(32,33,'g'), (37,37,'h'), (33,33,'i'), (33,32,'j'), (32,32,'k'), (35,35,'l'),
(44,45,'a'), (47,48,'b'), (44,43,'c'), (41,42,'d'), (42,41,'e'), (45,45,'f'),
(42,43,'g'), (47,47,'h'), (43,43,'i'), (43,42,'j'), (42,42,'k'), (45,45,'l');
# join order: (t1,t2) with ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 6 Using index condition; Rowid-ordered scan
1 SIMPLE t2 ref idx1,idx2 idx1 5 test.t1.a 12 Using where
explain format=json select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 6,
"filtered": 100,
"index_condition": "t1.a is not null",
"mrr_type": "Rowid-ordered scan"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx1", "idx2"],
"key": "idx1",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 12,
"filtered": 100,
"attached_condition": "(t1.a,t2.e) in (<cache>((3,3)),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1;
a b c d e f
3 3 zzzz 3 3 i
3 3 zzzz 3 3 i
7 8 xxxxx 7 7 h
7 7 xxxyy 7 7 h
3 3 zyxw 3 3 i
3 3 zyxw 3 3 i
3 2 uuuw 3 3 i
3 2 uuuw 3 3 i
3 3 zzza 3 3 i
3 3 zzza 3 3 i
7 8 xxxxa 7 7 h
7 7 xxxya 7 7 h
3 3 zyxa 3 3 i
3 3 zyxa 3 3 i
3 2 uuua 3 3 i
3 2 uuua 3 3 i
prepare stmt from "select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1";
execute stmt;
a b c d e f
3 3 zzzz 3 3 i
3 3 zzzz 3 3 i
7 8 xxxxx 7 7 h
7 7 xxxyy 7 7 h
3 3 zyxw 3 3 i
3 3 zyxw 3 3 i
3 2 uuuw 3 3 i
3 2 uuuw 3 3 i
3 3 zzza 3 3 i
3 3 zzza 3 3 i
7 8 xxxxa 7 7 h
7 7 xxxya 7 7 h
3 3 zyxa 3 3 i
3 3 zyxa 3 3 i
3 2 uuua 3 3 i
3 2 uuua 3 3 i
execute stmt;
a b c d e f
3 3 zzzz 3 3 i
3 3 zzzz 3 3 i
7 8 xxxxx 7 7 h
7 7 xxxyy 7 7 h
3 3 zyxw 3 3 i
3 3 zyxw 3 3 i
3 2 uuuw 3 3 i
3 2 uuuw 3 3 i
3 3 zzza 3 3 i
3 3 zzza 3 3 i
7 8 xxxxa 7 7 h
7 7 xxxya 7 7 h
3 3 zyxa 3 3 i
3 3 zyxa 3 3 i
3 2 uuua 3 3 i
3 2 uuua 3 3 i
deallocate prepare stmt;
insert into t1 select * from t1;
# join order: (t2,t1) with ref access of t1
# range access to t2 by keys for index idx2
explain select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range idx1,idx2 idx2 5 NULL 6 Using where; Rowid-ordered scan
1 SIMPLE t1 ref idx idx 5 test.t2.d 11
explain format=json select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["idx1", "idx2"],
"key": "idx2",
"key_length": "5",
"used_key_parts": ["e"],
"rows": 6,
"filtered": 100,
"attached_condition": "(t2.d,t2.e) in (<cache>((4,4)),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1 and t2.d is not null",
"mrr_type": "Rowid-ordered scan"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.d"],
"rows": 11,
"filtered": 100
}
}
}
select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
a b c d e f
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
alter table t2 drop index idx1, drop index idx2, add index idx3(d,e);
# join order: (t2,t1) with ref access of t1
# range access to t2 by 2-component keys for index idx3
explain select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range idx3 idx3 10 NULL 5 Using index condition; Using where; Rowid-ordered scan
1 SIMPLE t1 ref idx idx 5 test.t2.d 11
explain format=json select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t2",
"access_type": "range",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "10",
"used_key_parts": ["d", "e"],
"rows": 5,
"filtered": 100,
"index_condition": "t2.d is not null",
"attached_condition": "(t2.d,t2.e) in (<cache>((4,4)),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1",
"mrr_type": "Rowid-ordered scan"
},
"table": {
"table_name": "t1",
"access_type": "ref",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"ref": ["test.t2.d"],
"rows": 11,
"filtered": 100
}
}
}
select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
a b c d e f
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 7 xxxyy 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
7 8 xxxxx 7 7 h
7 8 xxxxa 7 7 h
# join order: (t1,t2) with ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2
where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 15 Using index condition; Rowid-ordered scan
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2
where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 15,
"filtered": 100,
"index_condition": "t1.a is not null",
"mrr_type": "Rowid-ordered scan"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1;
a b c d e f
4 5 ww 4 5 a
7 8 xxxxx 7 8 b
4 3 zyx 4 5 a
7 7 xxxyy 7 8 b
4 5 wa 4 5 a
7 8 xxxxa 7 8 b
4 3 zya 4 5 a
7 7 xxxya 7 8 b
4 5 ww 4 5 a
7 8 xxxxx 7 8 b
4 3 zyx 4 5 a
7 7 xxxyy 7 8 b
4 5 wa 4 5 a
7 8 xxxxa 7 8 b
4 3 zya 4 5 a
7 7 xxxya 7 8 b
# join order: (t1,t2) with ref access of t2
# no range access
explain select * from t1,t2
where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL idx NULL NULL NULL 144 Using where
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2
where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"possible_keys": ["idx"],
"rows": 144,
"filtered": 100,
"attached_condition": "t1.a is not null"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),<cache>((7,7)),<cache>((8,8))) and length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1;
a b c d e f
7 8 xxxxx 7 7 h
7 7 xxxyy 7 7 h
7 8 xxxxa 7 7 h
7 7 xxxya 7 7 h
7 8 xxxxx 7 7 h
7 7 xxxyy 7 7 h
7 8 xxxxa 7 7 h
7 7 xxxya 7 7 h
# join order: (t1,t2) with ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where; Rowid-ordered scan
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 13,
"filtered": 100,
"index_condition": "t1.a is not null",
"attached_condition": "(t1.a,2) in (<cache>((2,2)),<cache>((7,7)),<cache>((8,8))) and length(t1.c) = 1",
"mrr_type": "Rowid-ordered scan"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "length(t2.f) = 1"
}
}
}
select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
a b c d e f
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
prepare stmt from "select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1";
execute stmt;
a b c d e f
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
execute stmt;
a b c d e f
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
2 1 w 2 1 e
2 1 w 2 2 k
2 1 w 2 3 g
deallocate prepare stmt;
create table t3 (id int primary key, v int) engine=myisam;
insert into t3 values
(3,2), (1,1), (4,12), (2,15);
# join order: (t3,t1,t2) with const t3 and ref access of t2
# range access to t1 by 1-component keys for index idx
explain select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1
1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where; Rowid-ordered scan
1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where
explain format=json select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t3",
"access_type": "const",
"possible_keys": ["PRIMARY"],
"key": "PRIMARY",
"key_length": "4",
"used_key_parts": ["id"],
"ref": ["const"],
"rows": 1,
"filtered": 100
},
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["idx"],
"key": "idx",
"key_length": "5",
"used_key_parts": ["a"],
"rows": 13,
"filtered": 100,
"index_condition": "t1.a is not null",
"attached_condition": "(t1.a,1 + 1) in (<cache>((2,2)),<cache>((7,7)),<cache>((8,8))) and length(t1.c) = 1",
"mrr_type": "Rowid-ordered scan"
},
"table": {
"table_name": "t2",
"access_type": "ref",
"possible_keys": ["idx3"],
"key": "idx3",
"key_length": "5",
"used_key_parts": ["d"],
"ref": ["test.t1.a"],
"rows": 3,
"filtered": 100,
"attached_condition": "length(t2.f) = 1"
}
}
}
select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
a b c d e f id v
2 1 w 2 1 e 1 1
2 1 w 2 2 k 1 1
2 1 w 2 3 g 1 1
2 1 w 2 1 e 1 1
2 1 w 2 2 k 1 1
2 1 w 2 3 g 1 1
# IN predicate is always FALSE
explain select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((9,9),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
prepare stmt from "select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((9,9),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1";
execute stmt;
a b c d e f id v
execute stmt;
a b c d e f id v
deallocate prepare stmt;
set optimizer_switch=@save_optimizer_switch;
drop table t1,t2,t3;
#
# End of 10.2 tests
#
set optimizer_switch=@mrr_icp_extra_tmp; set optimizer_switch=@mrr_icp_extra_tmp;

View File

@@ -1857,3 +1857,195 @@ DROP TABLE t1;
--echo # --echo #
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --echo #
--echo #
--echo # MDEV-10454: range access keys extracted
--echo # from <row> IN (<row value list>)
--echo #
create table t1(a int, b int, c varchar(16), key idx(a,b)) engine=myisam;
insert into t1 values
(1,1,'xx'), (2,2,'yyy'), (3,3,'zzzz'), (1,2,'zz'), (1,3,'x'),
(2,3,'yy'), (4,5,'ww'), (7,8,'xxxxx'), (4,3,'zyx'), (1,2,'uuu'),
(2,1,'w'), (5,5,'wx'), (2,3,'ww'), (7,7,'xxxyy'), (3,3,'zyxw'),
(3,2,'uuuw'), (2,2,'wxz'), (5,5,'xw'), (12,12,'xx'), (12,12,'y'),
(13,13,'z'), (11,12,'zz'), (11,13,'x'), (12,13,'y'), (14,15,'w'),
(17,18,'xx'), (14,13,'zx'), (11,12,'u'), (12,11,'w'), (5,5,'wx'),
(12,13,'ww'), (17,17,'xxxyy'), (13,13,'zyxw'), (13,12,'uuuw'), (12,12,'wxz'),
(15,15,'xw'), (1,1,'xa'), (2,2,'yya'), (3,3,'zzza'), (1,2,'za'),
(1,3,'xb'), (2,3,'ya'), (4,5,'wa'), (7,8,'xxxxa'), (4,3,'zya'),
(1,2,'uua'), (2,1,'wb'), (5,5,'wc'), (2,3,'wa'), (7,7,'xxxya'),
(3,3,'zyxa'), (3,2,'uuua'), (2,2,'wxa'), (5,5,'xa'), (12,12,'xa'),
(22,12,'yb'), (23,13,'zb'), (21,12,'za'), (24,13,'c'), (32,13,'d'),
(34,15,'wd'), (47,18,'xa'), (54,13,'za'), (51,12,'ub'), (52,11,'wc'),
(5,5,'wd'), (62,13,'wa'), (67,17,'xxxya'), (63,13,'zyxa'), (73,12,'uuua'),
(82,12,'wxa'), (85,15,'xd');
--echo # range access to t1 by 2-component keys for index idx
let $q1=
select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7));
eval explain $q1;
eval explain format=json $q1;
eval $q1;
eval prepare stmt from "$q1";
execute stmt;
execute stmt;
deallocate prepare stmt;
--echo # range access to t1 by 1-component keys for index idx
let $q2=
select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7));
eval explain $q2;
eval explain format=json $q2;
eval $q2;
--echo # range access to t1 by 1-component keys for index idx
let $q3=
select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7));
eval explain $q3;
eval explain format=json $q3;
eval $q3;
# this setting should be removed after fixes for mdev-12186, mdev-12187
set @save_optimizer_switch=@@optimizer_switch;
set optimizer_switch='index_merge=off';
create table t2(
d int, e int, key idx1(d), key idx2(e), f varchar(32)
) engine=myisam;
insert into t2 values
(9,5,'a'), (9,8,'b'), (9,3,'c'), (9,2,'d'), (9,1,'e'),
(6,5,'f'), (6,3,'g'), (6,7,'h'), (3,3,'i'), (6,2,'j'),
(9,5,'aa'), (9,8,'ba'), (9,3,'ca'), (2,2,'da'), (9,1,'ea'),
(6,5,'fa'), (6,3,'ga'), (6,7,'ha'), (9,3,'ia'), (6,2,'ja');
--echo # join order: (t2,t1) with ref access of t1
--echo # range access to t1 by keys for index idx1
let $q4=
select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(2,2));
eval explain $q4;
eval explain format=json $q4;
eval $q4;
insert into t2 values
(4,5,'a'), (7,8,'b'), (4,3,'c'), (1,2,'d'), (2,1,'e'), (5,5,'f'),
(2,3,'g'), (7,7,'h'), (3,3,'i'), (3,2,'j'), (2,2,'k'), (5,5,'l'),
(4,5,'aa'), (7,8,'bb'), (4,3,'cc'), (1,2,'dd'), (2,1,'ee'), (9,5,'ff'),
(2,3,'gg'), (7,7,'hh'), (3,3,'ii'), (3,2,'jj'), (2,2,'kk'), (9,5,'ll'),
(4,5,'aaa'), (7,8,'bbb'), (4,3,'ccc'), (1,2,'ddd'), (2,1,'eee'), (5,5,'fff'),
(2,3,'ggg'), (7,7,'hhh'), (3,3,'iii'), (3,2,'jjj'), (2,2,'kkk'), (5,5,'lll'),
(14,15,'a'), (17,18,'b'), (14,13,'c'), (11,12,'d'), (12,11,'e'), (15,15,'f'),
(12,13,'g'), (17,17,'h'), (13,13,'i'), (13,12,'j'), (12,12,'k'), (15,15,'l'),
(24,25,'a'), (27,28,'b'), (24,23,'c'), (21,22,'d'), (22,21,'e'), (25,25,'f'),
(22,23,'g'), (27,27,'h'), (23,23,'i'), (23,22,'j'), (22,22,'k'), (25,25,'l'),
(34,35,'a'), (37,38,'b'), (34,33,'c'), (31,32,'d'), (32,31,'e'), (35,35,'f'),
(32,33,'g'), (37,37,'h'), (33,33,'i'), (33,32,'j'), (32,32,'k'), (35,35,'l'),
(44,45,'a'), (47,48,'b'), (44,43,'c'), (41,42,'d'), (42,41,'e'), (45,45,'f'),
(42,43,'g'), (47,47,'h'), (43,43,'i'), (43,42,'j'), (42,42,'k'), (45,45,'l');
--echo # join order: (t1,t2) with ref access of t2
--echo # range access to t1 by 1-component keys for index idx
let $q5=
select * from t1,t2
where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1;
eval explain $q5;
eval explain format=json $q5;
eval $q5;
eval prepare stmt from "$q5";
execute stmt;
execute stmt;
deallocate prepare stmt;
insert into t1 select * from t1;
--echo # join order: (t2,t1) with ref access of t1
--echo # range access to t2 by keys for index idx2
let $q6=
select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
eval explain $q6;
eval explain format=json $q6;
eval $q6;
alter table t2 drop index idx1, drop index idx2, add index idx3(d,e);
--echo # join order: (t2,t1) with ref access of t1
--echo # range access to t2 by 2-component keys for index idx3
let $q7=
select * from t1,t2
where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1;
eval explain $q7;
eval explain format=json $q7;
eval $q7;
--echo # join order: (t1,t2) with ref access of t2
--echo # range access to t1 by 1-component keys for index idx
let $q8=
select * from t1,t2
where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1;
eval explain $q8;
eval explain format=json $q8;
eval $q8;
--echo # join order: (t1,t2) with ref access of t2
--echo # no range access
let $q9=
select * from t1,t2
where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1;
eval explain $q9;
eval explain format=json $q9;
eval $q9;
--echo # join order: (t1,t2) with ref access of t2
--echo # range access to t1 by 1-component keys for index idx
let $q10=
select * from t1,t2
where a = d and (a,2) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
eval explain $q10;
eval explain format=json $q10;
eval $q10;
eval prepare stmt from "$q10";
execute stmt;
execute stmt;
deallocate prepare stmt;
create table t3 (id int primary key, v int) engine=myisam;
insert into t3 values
(3,2), (1,1), (4,12), (2,15);
--echo # join order: (t3,t1,t2) with const t3 and ref access of t2
--echo # range access to t1 by 1-component keys for index idx
let $q11=
select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((2,2),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
eval explain $q11;
eval explain format=json $q11;
eval $q11;
--echo # IN predicate is always FALSE
let $q12=
select * from t1,t2,t3
where id = 1 and a = d and
(a,v+1) in ((9,9),(7,7),(8,8)) and
length(c) = 1 and length(f) = 1;
eval explain $q12;
eval prepare stmt from "$q12";
execute stmt;
execute stmt;
deallocate prepare stmt;
set optimizer_switch=@save_optimizer_switch;
drop table t1,t2,t3;
--echo #
--echo # End of 10.2 tests
--echo #

View File

@@ -51,10 +51,11 @@ ENDIF()
FIND_LIBRARY(AWS_CPP_SDK_CORE NAMES aws-cpp-sdk-core PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") FIND_LIBRARY(AWS_CPP_SDK_CORE NAMES aws-cpp-sdk-core PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}")
FIND_LIBRARY(AWS_CPP_SDK_KMS NAMES aws-cpp-sdk-kms PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") FIND_LIBRARY(AWS_CPP_SDK_KMS NAMES aws-cpp-sdk-kms PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}")
SET(CMAKE_REQUIRED_FLAGS ${CXX11_FLAGS}) SET(CMAKE_REQUIRED_FLAGS ${CXX11_FLAGS})
CHECK_INCLUDE_FILE_CXX(aws/kms/KMSClient.h HAVE_AWS_HEADERS) FIND_PATH(AWS_CPP_SDK_INCLUDE_DIR NAMES aws/kms/KMSClient.h)
IF(AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND HAVE_AWS_HEADERS) IF(AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND AWS_CPP_SDK_INCLUDE_DIR)
# AWS C++ SDK installed # AWS C++ SDK installed
INCLUDE_DIRECTORIES(${AWS_CPP_SDK_INCLUDE_DIR})
SET(AWS_SDK_LIBS ${AWS_CPP_SDK_CORE} ${AWS_CPP_SDK_KMS}) SET(AWS_SDK_LIBS ${AWS_CPP_SDK_CORE} ${AWS_CPP_SDK_KMS})
ELSE() ELSE()
OPTION(AWS_SDK_EXTERNAL_PROJECT "Allow download and build AWS C++ SDK" OFF) OPTION(AWS_SDK_EXTERNAL_PROJECT "Allow download and build AWS C++ SDK" OFF)
@@ -95,14 +96,28 @@ ELSE()
SET(EXTRA_SDK_CMAKE_FLAGS ${EXTRA_SDK_CMAKE_FLAGS} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) SET(EXTRA_SDK_CMAKE_FLAGS ${EXTRA_SDK_CMAKE_FLAGS} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
ENDIF() ENDIF()
SET(byproducts )
# We do not need to build the whole SDK , just 2 of its libs
set(AWS_SDK_LIBS aws-cpp-sdk-core aws-cpp-sdk-kms)
FOREACH(lib ${AWS_SDK_LIBS})
ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL)
ADD_DEPENDENCIES(${lib} aws_sdk_cpp)
SET(loc "${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}")
IF(CMAKE_VERSION VERSION_GREATER "3.1")
SET(byproducts ${byproducts} BUILD_BYPRODUCTS ${loc})
ENDIF()
SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc})
ENDFOREACH()
SET(AWS_SDK_PATCH_COMMAND ) SET(AWS_SDK_PATCH_COMMAND )
ExternalProject_Add( ExternalProject_Add(
aws_sdk_cpp aws_sdk_cpp
GIT_REPOSITORY "https://github.com/awslabs/aws-sdk-cpp.git" GIT_REPOSITORY "https://github.com/awslabs/aws-sdk-cpp.git"
GIT_TAG "1.0.8" GIT_TAG "1.0.8"
UPDATE_COMMAND "" UPDATE_COMMAND ""
SOURCE_DIR "${CMAKE_BINARY_DIR}/aws-sdk-cpp" SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/aws-sdk-cpp"
CMAKE_ARGS ${byproducts}
CMAKE_ARGS
-DBUILD_ONLY=kms -DBUILD_ONLY=kms
-DBUILD_SHARED_LIBS=OFF -DBUILD_SHARED_LIBS=OFF
-DFORCE_SHARED_CRT=OFF -DFORCE_SHARED_CRT=OFF
@@ -111,34 +126,28 @@ ELSE()
"-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} ${PIC_FLAG}" "-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} ${PIC_FLAG}"
"-DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL} ${PIC_FLAG}" "-DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL} ${PIC_FLAG}"
${EXTRA_SDK_CMAKE_FLAGS} ${EXTRA_SDK_CMAKE_FLAGS}
-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/aws_sdk_cpp -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp
TEST_COMMAND "" TEST_COMMAND ""
) )
SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE)
# We do not need to build the whole SDK , just 2 of its libs
set(AWS_SDK_LIBS aws-cpp-sdk-core aws-cpp-sdk-kms)
FOREACH(lib ${AWS_SDK_LIBS})
ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL)
ADD_DEPENDENCIES(${lib} aws_sdk_cpp)
SET(loc "${CMAKE_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}")
SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc})
IF(WIN32)
SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "bcrypt;winhttp;wininet;userenv")
ELSE()
SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "${SSL_LIBRARIES};${CURL_LIBRARIES};${UUID_LIBRARIES}")
ENDIF()
ENDFOREACH()
IF(CMAKE_SYSTEM_NAME MATCHES "Linux") IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
# Need whole-archive , otherwise static libraries are not linked # Need whole-archive , otherwise static libraries are not linked
SET(AWS_SDK_LIBS -Wl,--whole-archive ${AWS_SDK_LIBS} -Wl,--no-whole-archive) SET(AWS_SDK_LIBS -Wl,--whole-archive ${AWS_SDK_LIBS} -Wl,--no-whole-archive)
ENDIF() ENDIF()
SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE)
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/aws_sdk_cpp/include) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/include)
ENDIF() ENDIF()
ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}")
IF(WIN32)
SET(AWS_CPP_SDK_DEPENDENCIES bcrypt winhttp wininet userenv version)
ELSE()
SET(AWS_CPP_SDK_DEPENDENCIES ${SSL_LIBRARIES} ${CURL_LIBRARIES} ${UUID_LIBRARIES})
ENDIF()
MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc
LINK_LIBRARIES ${AWS_SDK_LIBS} LINK_LIBRARIES ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES}
COMPONENT aws-key-management) COMPONENT aws-key-management)

View File

@@ -1662,6 +1662,7 @@ public:
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
table_map usable_tables, SARGABLE_PARAM **sargables); table_map usable_tables, SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr); SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
SEL_TREE *get_func_row_mm_tree(RANGE_OPT_PARAM *param, Item_row *key_row);
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{ {
/* /*
@@ -1714,6 +1715,7 @@ public:
cmp_item *make_same(); cmp_item *make_same();
void store_value_by_template(THD *thd, cmp_item *tmpl, Item *); void store_value_by_template(THD *thd, cmp_item *tmpl, Item *);
friend void Item_func_in::fix_length_and_dec(); friend void Item_func_in::fix_length_and_dec();
cmp_item *get_comparator(uint i) { return comparators[i]; }
}; };
@@ -1727,6 +1729,7 @@ public:
uchar *get_value(Item *item); uchar *get_value(Item *item);
friend void Item_func_in::fix_length_and_dec(); friend void Item_func_in::fix_length_and_dec();
Item_result result_type() { return ROW_RESULT; } Item_result result_type() { return ROW_RESULT; }
cmp_item *get_cmp_item() { return &tmp; }
}; };
/* Functions used by where clause */ /* Functions used by where clause */

View File

@@ -119,6 +119,13 @@ public:
bool check_cols(uint c); bool check_cols(uint c);
bool null_inside() { return with_null; }; bool null_inside() { return with_null; };
void bring_value(); void bring_value();
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
Item_args::propagate_equal_fields(thd, Context_identity(), cond);
return this;
}
bool check_vcol_func_processor(void *arg) {return FALSE; } bool check_vcol_func_processor(void *arg) {return FALSE; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_row>(thd, mem_root, this); } { return get_item_copy<Item_row>(thd, mem_root, this); }

View File

@@ -7210,6 +7210,205 @@ SEL_TREE *Item_func_in::get_func_mm_tree(RANGE_OPT_PARAM *param,
} }
/*
The structure Key_col_info is purely auxiliary and is used
only in the method Item_func_in::get_func_row_mm_tree
*/
struct Key_col_info {
Field *field; /* If != NULL the column can be used for keys */
cmp_item *comparator; /* If != 0 the column can be evaluated */
};
/**
Build SEL_TREE for the IN predicate whose arguments are rows
@param param PARAM from SQL_SELECT::test_quick_select
@param key_row First operand of the IN predicate
@note
The function builds a SEL_TREE for in IN predicate in the case
when the predicate uses row arguments. First the function
detects among the components of the key_row (c[1],...,c[n]) taken
from in the left part the predicate those that can be usable
for building SEL_TREE (c[i1],...,c[ik]). They have to contain
items whose real items are field items referring to the current
table or equal to the items referring to the current table.
For the remaining components of the row it checks whether they
can be evaluated. The result of the analysis is put into the
array of structures of the type Key_row_col_info.
After this the function builds the SEL_TREE for the following
formula that can be inferred from the given IN predicate:
c[i11]=a[1][i11] AND ... AND c[i1k1]=a[1][i1k1]
OR
...
OR
c[im1]=a[m][im1] AND ... AND c[imkm]=a[m][imkm].
Here a[1],...,a[m] are all arguments of the IN predicate from
the right part and for each j ij1,...,ijkj is a subset of
i1,...,ik such that a[j][ij1],...,a[j][ijkj] can be evaluated.
If for some j there no a[j][i1],...,a[j][ik] can be evaluated
then no SEL_TREE can be built for this predicate and the
function immediately returns 0.
If for some j by using evaluated values of key_row it can be
proven that c[ij1]=a[j][ij1] AND ... AND c[ijkj]=a[j][ijkj]
is always FALSE then this disjunct is omitted.
@returns
the built SEL_TREE if it can be constructed
0 - otherwise.
*/
SEL_TREE *Item_func_in::get_func_row_mm_tree(RANGE_OPT_PARAM *param,
Item_row *key_row)
{
DBUG_ENTER("Item_func_in::get_func_row_mm_tree");
if (negated)
DBUG_RETURN(0);
SEL_TREE *res_tree= 0;
uint used_key_cols= 0;
uint col_comparators= 0;
table_map param_comp= ~(param->prev_tables | param->read_tables |
param->current_table);
uint row_cols= key_row->cols();
Dynamic_array <Key_col_info> key_cols_info(row_cols);
cmp_item_row *row_cmp_item= (cmp_item_row *)
(array ? ((in_row *) array)->get_cmp_item() :
cmp_items[(uint) ROW_RESULT]);
Item **key_col_ptr= key_row->addr(0);
for(uint i= 0; i < row_cols; i++, key_col_ptr++)
{
Key_col_info key_col_info= {0, NULL};
Item *key_col= *key_col_ptr;
if (key_col->real_item()->type() == Item::FIELD_ITEM)
{
/*
The i-th component of key_row can be used for key access if
key_col->real_item() points to a field of the current table or
if it is equal to a field item pointing to such a field.
*/
Item_field *col_field_item= (Item_field *) (key_col->real_item());
Field *key_col_field= col_field_item->field;
if (key_col_field->table->map != param->current_table)
{
Item_equal *item_equal= col_field_item->item_equal;
if (item_equal)
{
Item_equal_fields_iterator it(*item_equal);
while (it++)
{
key_col_field= it.get_curr_field();
if (key_col_field->table->map == param->current_table)
break;
}
}
}
if (key_col_field->table->map == param->current_table)
{
key_col_info.field= key_col_field;
used_key_cols++;
}
}
else if (!(key_col->used_tables() & (param_comp | param->current_table))
&& !key_col->is_expensive())
{
/* The i-th component of key_row can be evaluated */
/* See the comment in Item::get_mm_tree_for_const */
MEM_ROOT *tmp_root= param->mem_root;
param->thd->mem_root= param->old_root;
key_col->bring_value();
key_col_info.comparator= row_cmp_item->get_comparator(i);
key_col_info.comparator->store_value(key_col);
col_comparators++;
param->thd->mem_root= tmp_root;
}
key_cols_info.push(key_col_info);
}
if (!used_key_cols)
DBUG_RETURN(0);
uint omitted_tuples= 0;
Item **arg_start= arguments() + 1;
Item **arg_end= arg_start + argument_count() - 1;
for (Item **arg= arg_start ; arg < arg_end; arg++)
{
uint i;
/*
First check whether the disjunct constructed for *arg
is really needed
*/
Item_row *arg_tuple= (Item_row *) (*arg);
if (col_comparators)
{
MEM_ROOT *tmp_root= param->mem_root;
param->thd->mem_root= param->old_root;
for (i= 0; i < row_cols; i++)
{
Key_col_info *key_col_info= &key_cols_info.at(i);
if (key_col_info->comparator)
{
Item *arg_col= arg_tuple->element_index(i);
if (!(arg_col->used_tables() & (param_comp | param->current_table)) &&
!arg_col->is_expensive() &&
key_col_info->comparator->cmp(arg_col))
{
omitted_tuples++;
break;
}
}
}
param->thd->mem_root= tmp_root;
if (i < row_cols)
continue;
}
/* The disjunct for *arg is needed: build it. */
SEL_TREE *and_tree= 0;
Item **arg_col_ptr= arg_tuple->addr(0);
for (uint i= 0; i < row_cols; i++, arg_col_ptr++)
{
Key_col_info *key_col_info= &key_cols_info.at(i);
if (!key_col_info->field)
continue;
Item *arg_col= *arg_col_ptr;
if (!(arg_col->used_tables() & (param_comp | param->current_table)) &&
!arg_col->is_expensive())
{
and_tree= tree_and(param, and_tree,
get_mm_parts(param,
key_col_info->field,
Item_func::EQ_FUNC,
arg_col->real_item()));
}
}
if (!and_tree)
{
res_tree= 0;
break;
}
/* Join the disjunct the the OR tree that is being constructed */
res_tree= !res_tree ? and_tree : tree_or(param, res_tree, and_tree);
}
if (omitted_tuples == argument_count() - 1)
{
/* It's turned out that all disjuncts are always FALSE */
res_tree= new (param->mem_root) SEL_TREE(SEL_TREE::IMPOSSIBLE,
param->mem_root, param->keys);
}
DBUG_RETURN(res_tree);
}
/* /*
Build conjunction of all SEL_TREEs for a simple predicate applying equalities Build conjunction of all SEL_TREEs for a simple predicate applying equalities
@@ -7544,12 +7743,22 @@ SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
if (const_item()) if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param)); DBUG_RETURN(get_mm_tree_for_const(param));
if (key_item()->real_item()->type() != Item::FIELD_ITEM) SEL_TREE *tree= 0;
switch (key_item()->real_item()->type()) {
case Item::FIELD_ITEM:
tree= get_full_func_mm_tree(param,
(Item_field*) (key_item()->real_item()),
NULL);
break;
case Item::ROW_ITEM:
tree= get_func_row_mm_tree(param,
(Item_row *) (key_item()->real_item()));
break;
default:
DBUG_RETURN(0); DBUG_RETURN(0);
Item_field *field= (Item_field*) (key_item()->real_item()); }
SEL_TREE *tree= get_full_func_mm_tree(param, field, NULL);
DBUG_RETURN(tree); DBUG_RETURN(tree);
} }
SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)

View File

@@ -4709,6 +4709,8 @@ static uint get_semi_join_select_list_index(Field *field)
@param num_values Number of values[] that we are comparing against @param num_values Number of values[] that we are comparing against
@param usable_tables Tables which can be used for key optimization @param usable_tables Tables which can be used for key optimization
@param sargables IN/OUT Array of found sargable candidates @param sargables IN/OUT Array of found sargable candidates
@param row_col_no if = n that > 0 then field is compared only
against the n-th component of row values
@note @note
If we are doing a NOT NULL comparison on a NOT NULL field in a outer join If we are doing a NOT NULL comparison on a NOT NULL field in a outer join
@@ -4722,7 +4724,8 @@ static void
add_key_field(JOIN *join, add_key_field(JOIN *join,
KEY_FIELD **key_fields,uint and_level, Item_bool_func *cond, KEY_FIELD **key_fields,uint and_level, Item_bool_func *cond,
Field *field, bool eq_func, Item **value, uint num_values, Field *field, bool eq_func, Item **value, uint num_values,
table_map usable_tables, SARGABLE_PARAM **sargables) table_map usable_tables, SARGABLE_PARAM **sargables,
uint row_col_no= 0)
{ {
uint optimize= 0; uint optimize= 0;
if (eq_func && if (eq_func &&
@@ -4751,7 +4754,15 @@ add_key_field(JOIN *join,
bool optimizable=0; bool optimizable=0;
for (uint i=0; i<num_values; i++) for (uint i=0; i<num_values; i++)
{ {
table_map value_used_tables= (value[i])->used_tables(); Item *curr_val;
if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM)
{
Item_row *value_tuple= (Item_row *) (value[i]->real_item());
curr_val= value_tuple->element_index(row_col_no - 1);
}
else
curr_val= value[i];
table_map value_used_tables= curr_val->used_tables();
used_tables|= value_used_tables; used_tables|= value_used_tables;
if (!(value_used_tables & (field->table->map | RAND_TABLE_BIT))) if (!(value_used_tables & (field->table->map | RAND_TABLE_BIT)))
optimizable=1; optimizable=1;
@@ -4789,7 +4800,15 @@ add_key_field(JOIN *join,
bool is_const=1; bool is_const=1;
for (uint i=0; i<num_values; i++) for (uint i=0; i<num_values; i++)
{ {
if (!(is_const&= value[i]->const_item())) Item *curr_val;
if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM)
{
Item_row *value_tuple= (Item_row *) (value[i]->real_item());
curr_val= value_tuple->element_index(row_col_no - 1);
}
else
curr_val= value[i];
if (!(is_const&= curr_val->const_item()))
break; break;
} }
if (is_const) if (is_const)
@@ -4856,12 +4875,14 @@ add_key_field(JOIN *join,
@param key_fields Pointer to add key, if usable @param key_fields Pointer to add key, if usable
@param and_level And level, to be stored in KEY_FIELD @param and_level And level, to be stored in KEY_FIELD
@param cond Condition predicate @param cond Condition predicate
@param field Field used in comparision @param field_item Field item used for comparison
@param eq_func True if we used =, <=> or IS NULL @param eq_func True if we used =, <=> or IS NULL
@param value Value used for comparison with field @param value Value used for comparison with field_item
Is NULL for BETWEEN and IN @param num_values Number of values[] that we are comparing against
@param usable_tables Tables which can be used for key optimization @param usable_tables Tables which can be used for key optimization
@param sargables IN/OUT Array of found sargable candidates @param sargables IN/OUT Array of found sargable candidates
@param row_col_no if = n that > 0 then field is compared only
against the n-th component of row values
@note @note
If field items f1 and f2 belong to the same multiple equality and If field items f1 and f2 belong to the same multiple equality and
@@ -4876,11 +4897,12 @@ add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level,
Item_bool_func *cond, Item *field_item, Item_bool_func *cond, Item *field_item,
bool eq_func, Item **val, bool eq_func, Item **val,
uint num_values, table_map usable_tables, uint num_values, table_map usable_tables,
SARGABLE_PARAM **sargables) SARGABLE_PARAM **sargables, uint row_col_no= 0)
{ {
Field *field= ((Item_field *) (field_item->real_item()))->field; Field *field= ((Item_field *) (field_item->real_item()))->field;
add_key_field(join, key_fields, and_level, cond, field, add_key_field(join, key_fields, and_level, cond, field,
eq_func, val, num_values, usable_tables, sargables); eq_func, val, num_values, usable_tables, sargables,
row_col_no);
Item_equal *item_equal= field_item->get_item_equal(); Item_equal *item_equal= field_item->get_item_equal();
if (item_equal) if (item_equal)
{ {
@@ -4896,7 +4918,7 @@ add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level,
{ {
add_key_field(join, key_fields, and_level, cond, equal_field, add_key_field(join, key_fields, and_level, cond, equal_field,
eq_func, val, num_values, usable_tables, eq_func, val, num_values, usable_tables,
sargables); sargables, row_col_no);
} }
} }
} }
@@ -5078,6 +5100,24 @@ Item_func_in::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
(Item_field*) (args[0]->real_item()), false, (Item_field*) (args[0]->real_item()), false,
args + 1, arg_count - 1, usable_tables, sargables); args + 1, arg_count - 1, usable_tables, sargables);
} }
else if (key_item()->type() == Item::ROW_ITEM &&
!(used_tables() & OUTER_REF_TABLE_BIT))
{
Item_row *key_row= (Item_row *) key_item();
Item **key_col= key_row->addr(0);
uint row_cols= key_row->cols();
for (uint i= 0; i < row_cols; i++, key_col++)
{
if (is_local_field(*key_col))
{
Item_field *field_item= (Item_field *)((*key_col)->real_item());
add_key_equal_fields(join, key_fields, *and_level, this,
field_item, false, args + 1, arg_count - 1,
usable_tables, sargables, i + 1);
}
}
}
} }

View File

@@ -136,15 +136,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table,
* if we don't lock to close a table, we check if space * if we don't lock to close a table, we check if space
* is closing, and then instead give up * is closing, and then instead give up
*/ */
if (lock_to_close_table == false) { if (lock_to_close_table) {
fil_space_t* space = fil_space_acquire(space_id); } else if (fil_space_t* space = fil_space_acquire(space_id)) {
if (!space || space->stop_new_ops) { bool stopping = space->is_stopping();
if (space) { fil_space_release(space);
fil_space_release(space); if (stopping) {
}
return false; return false;
} }
fil_space_release(space); } else {
return false;
} }
os_thread_sleep(250000); os_thread_sleep(250000);
@@ -206,18 +206,15 @@ btr_scrub_table_close_for_thread(
return; return;
} }
fil_space_t* space = fil_space_acquire(scrub_data->space); if (fil_space_t* space = fil_space_acquire(scrub_data->space)) {
/* If tablespace is not marked as stopping perform
/* If tablespace is not marked as stopping perform the actual close. */
the actual close. */ if (!space->is_stopping()) {
if (space && !space->is_stopping()) { mutex_enter(&dict_sys->mutex);
mutex_enter(&dict_sys->mutex); /* perform the actual closing */
/* perform the actual closing */ btr_scrub_table_close(scrub_data->current_table);
btr_scrub_table_close(scrub_data->current_table); mutex_exit(&dict_sys->mutex);
mutex_exit(&dict_sys->mutex); }
}
if (space) {
fil_space_release(space); fil_space_release(space);
} }

View File

@@ -7535,12 +7535,12 @@ buf_page_decrypt_after_read(buf_page_t* bpage)
return (true); return (true);
} }
FilSpace space(bpage->id.space()); FilSpace space(bpage->id.space(), true);
/* Page is encrypted if encryption information is found from /* Page is encrypted if encryption information is found from
tablespace and page contains used key_version. This is true tablespace and page contains used key_version. This is true
also for pages first compressed and then encrypted. */ also for pages first compressed and then encrypted. */
if (!space()->crypt_data) { if (!space() || !space()->crypt_data) {
key_version = 0; key_version = 0;
} }

View File

@@ -2268,12 +2268,13 @@ Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@param[in] silent whether to silently ignore missing tablespaces @param[in] silent whether to silently ignore missing tablespaces
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
inline inline
fil_space_t* fil_space_t*
fil_space_acquire_low( fil_space_acquire_low(ulint id, bool silent, bool for_io = false)
ulint id,
bool silent)
{ {
fil_space_t* space; fil_space_t* space;
@@ -2286,7 +2287,7 @@ fil_space_acquire_low(
ib::warn() << "Trying to access missing" ib::warn() << "Trying to access missing"
" tablespace " << id; " tablespace " << id;
} }
} else if (space->stop_new_ops || space->is_being_truncated) { } else if (!for_io && space->is_stopping()) {
space = NULL; space = NULL;
} else { } else {
space->n_pending_ops++; space->n_pending_ops++;
@@ -2301,22 +2302,24 @@ fil_space_acquire_low(
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io)
ulint id)
{ {
return(fil_space_acquire_low(id, false)); return(fil_space_acquire_low(id, false, for_io));
} }
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
{ {
return(fil_space_acquire_low(id, true)); return(fil_space_acquire_low(id, true));
} }
@@ -2324,8 +2327,7 @@ fil_space_acquire_silent(
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space)
fil_space_t* space)
{ {
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
@@ -5479,8 +5481,7 @@ fil_flush(
if (fil_space_t* space = fil_space_get_by_id(space_id)) { if (fil_space_t* space = fil_space_get_by_id(space_id)) {
if (space->purpose != FIL_TYPE_TEMPORARY if (space->purpose != FIL_TYPE_TEMPORARY
&& !space->stop_new_ops && !space->is_stopping()) {
&& !space->is_being_truncated) {
fil_flush_low(space); fil_flush_low(space);
} }
} }
@@ -5524,8 +5525,7 @@ fil_flush_file_spaces(
space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
if (space->purpose == purpose if (space->purpose == purpose
&& !space->stop_new_ops && !space->is_stopping()) {
&& !space->is_being_truncated) {
space_ids[n_space_ids++] = space->id; space_ids[n_space_ids++] = space->id;
} }
@@ -6701,8 +6701,7 @@ If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t. @return pointer to the next fil_space_t.
@retval NULL if this was the last*/ @retval NULL if this was the last*/
fil_space_t* fil_space_t*
fil_space_next( fil_space_next(fil_space_t* prev_space)
fil_space_t* prev_space)
{ {
fil_space_t* space=prev_space; fil_space_t* space=prev_space;
@@ -6725,8 +6724,8 @@ fil_space_next(
fil_ibd_create(), or dropped, or !tablespace. */ fil_ibd_create(), or dropped, or !tablespace. */
while (space != NULL while (space != NULL
&& (UT_LIST_GET_LEN(space->chain) == 0 && (UT_LIST_GET_LEN(space->chain) == 0
|| space->stop_new_ops || space->is_stopping()
|| space->purpose != FIL_TYPE_TABLESPACE)) { || space->purpose != FIL_TYPE_TABLESPACE)) {
space = UT_LIST_GET_NEXT(space_list, space); space = UT_LIST_GET_NEXT(space_list, space);
} }

View File

@@ -735,27 +735,28 @@ MY_ATTRIBUTE((warn_unused_result));
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io = false)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space);
fil_space_t* space);
/** Return the next fil_space_t. /** Return the next fil_space_t.
Once started, the caller must keep calling this until it returns NULL. Once started, the caller must keep calling this until it returns NULL.
@@ -792,17 +793,19 @@ public:
FilSpace() : m_space(NULL) {} FilSpace() : m_space(NULL) {}
/** Constructor: Look up the tablespace and increment the /** Constructor: Look up the tablespace and increment the
referece count if found. reference count if found.
@param[in] space_id tablespace ID */ @param[in] space_id tablespace ID
explicit FilSpace(ulint space_id) @param[in] for_io whether to look up the tablespace
: m_space(fil_space_acquire(space_id)) {} while performing I/O
(possibly executing TRUNCATE) */
explicit FilSpace(ulint space_id, bool for_io = false)
: m_space(fil_space_acquire(space_id, for_io)) {}
/** Assignment operator: This assumes that fil_space_acquire() /** Assignment operator: This assumes that fil_space_acquire()
has already been done for the fil_space_t. The caller must has already been done for the fil_space_t. The caller must
assign NULL if it calls fil_space_release(). assign NULL if it calls fil_space_release().
@param[in] space tablespace to assign */ @param[in] space tablespace to assign */
class FilSpace& operator=( class FilSpace& operator=(fil_space_t* space)
fil_space_t* space)
{ {
/* fil_space_acquire() must have been invoked. */ /* fil_space_acquire() must have been invoked. */
ut_ad(space == NULL || space->n_pending_ops > 0); ut_ad(space == NULL || space->n_pending_ops > 0);

View File

@@ -129,15 +129,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table,
* if we don't lock to close a table, we check if space * if we don't lock to close a table, we check if space
* is closing, and then instead give up * is closing, and then instead give up
*/ */
if (lock_to_close_table == false) { if (lock_to_close_table) {
fil_space_t* space = fil_space_acquire(space_id); } else if (fil_space_t* space = fil_space_acquire(space_id)) {
if (!space || space->stop_new_ops) { bool stopping = space->is_stopping();
if (space) { fil_space_release(space);
fil_space_release(space); if (stopping) {
}
return false; return false;
} }
fil_space_release(space); } else {
return false;
} }
os_thread_sleep(250000); os_thread_sleep(250000);
@@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread(
return; return;
} }
fil_space_t* space = fil_space_acquire(scrub_data->space); if (fil_space_t* space = fil_space_acquire(scrub_data->space)) {
/* If tablespace is not marked as stopping perform
/* If tablespace is not marked as stopping perform the actual close. */
the actual close. */ if (!space->is_stopping()) {
if (space && !space->is_stopping()) { mutex_enter(&dict_sys->mutex);
mutex_enter(&dict_sys->mutex); /* perform the actual closing */
/* perform the actual closing */ btr_scrub_table_close(scrub_data->current_table);
btr_scrub_table_close(scrub_data->current_table); mutex_exit(&dict_sys->mutex);
mutex_exit(&dict_sys->mutex); }
}
if (space) {
fil_space_release(space); fil_space_release(space);
} }

View File

@@ -6413,14 +6413,12 @@ buf_page_decrypt_after_read(
return (true); return (true);
} }
fil_space_t* space = fil_space_acquire(bpage->space); fil_space_t* space = fil_space_acquire(bpage->space, true);
fil_space_crypt_t* crypt_data = space->crypt_data;
/* Page is encrypted if encryption information is found from /* Page is encrypted if encryption information is found from
tablespace and page contains used key_version. This is true tablespace and page contains used key_version. This is true
also for pages first compressed and then encrypted. */ also for pages first compressed and then encrypted. */
if (!crypt_data) { if (!space || !space->crypt_data) {
key_version = 0; key_version = 0;
} }
@@ -6504,6 +6502,8 @@ buf_page_decrypt_after_read(
} }
} }
fil_space_release(space); if (space != NULL) {
fil_space_release(space);
}
return (success); return (success);
} }

View File

@@ -6389,16 +6389,12 @@ fil_flush(
{ {
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
fil_space_t* space = fil_space_get_by_id(space_id); if (fil_space_t* space = fil_space_get_by_id(space_id)) {
if (!space->is_stopping()) {
if (!space || space->stop_new_ops) { fil_flush_low(space);
mutex_exit(&fil_system->mutex); }
return;
} }
fil_flush_low(space);
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
} }
@@ -6438,8 +6434,7 @@ fil_flush_file_spaces(
space; space;
space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
if (space->purpose == purpose && !space->stop_new_ops) { if (space->purpose == purpose && !space->is_stopping()) {
space_ids[n_space_ids++] = space->id; space_ids[n_space_ids++] = space->id;
} }
} }
@@ -7388,12 +7383,13 @@ Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@param[in] silent whether to silently ignore missing tablespaces @param[in] silent whether to silently ignore missing tablespaces
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
inline inline
fil_space_t* fil_space_t*
fil_space_acquire_low( fil_space_acquire_low(ulint id, bool silent, bool for_io = false)
ulint id,
bool silent)
{ {
fil_space_t* space; fil_space_t* space;
@@ -7407,7 +7403,7 @@ fil_space_acquire_low(
" tablespace " ULINTPF ".", id); " tablespace " ULINTPF ".", id);
ut_error; ut_error;
} }
} else if (space->stop_new_ops) { } else if (!for_io && space->is_stopping()) {
space = NULL; space = NULL;
} else { } else {
space->n_pending_ops++; space->n_pending_ops++;
@@ -7422,22 +7418,24 @@ fil_space_acquire_low(
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io)
ulint id)
{ {
return(fil_space_acquire_low(id, false)); return(fil_space_acquire_low(id, false, for_io));
} }
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
{ {
return(fil_space_acquire_low(id, true)); return(fil_space_acquire_low(id, true));
} }
@@ -7445,8 +7443,7 @@ fil_space_acquire_silent(
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space)
fil_space_t* space)
{ {
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
@@ -7464,8 +7461,7 @@ If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t. @return pointer to the next fil_space_t.
@retval NULL if this was the last*/ @retval NULL if this was the last*/
fil_space_t* fil_space_t*
fil_space_next( fil_space_next(fil_space_t* prev_space)
fil_space_t* prev_space)
{ {
fil_space_t* space=prev_space; fil_space_t* space=prev_space;
@@ -7488,8 +7484,8 @@ fil_space_next(
fil_ibd_create(), or dropped, or !tablespace. */ fil_ibd_create(), or dropped, or !tablespace. */
while (space != NULL while (space != NULL
&& (UT_LIST_GET_LEN(space->chain) == 0 && (UT_LIST_GET_LEN(space->chain) == 0
|| space->stop_new_ops || space->is_stopping()
|| space->purpose != FIL_TABLESPACE)) { || space->purpose != FIL_TABLESPACE)) {
space = UT_LIST_GET_NEXT(space_list, space); space = UT_LIST_GET_NEXT(space_list, space);
} }

View File

@@ -650,27 +650,28 @@ fil_write_flushed_lsn_to_data_files(
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io = false)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space);
fil_space_t* space);
/** Return the next fil_space_t. /** Return the next fil_space_t.
Once started, the caller must keep calling this until it returns NULL. Once started, the caller must keep calling this until it returns NULL.