diff options
author | Sergei Petrunia <psergey@askmonty.org> | 2017-04-04 17:12:06 +0300 |
---|---|---|
committer | Sergei Petrunia <psergey@askmonty.org> | 2017-04-04 17:12:06 +0300 |
commit | fb0b3640fe2616f8f3168f8e487bb04f757e3eb1 (patch) | |
tree | 2b14836d33539764be4651b4b143dc5e29cff6fb | |
parent | c85ea1ab6d276f90b7b73d99cf357e11ea103822 (diff) | |
parent | 6d417a0bad205a6bacfee10dbc46dd631b093e75 (diff) | |
download | mariadb-git-fb0b3640fe2616f8f3168f8e487bb04f757e3eb1.tar.gz |
Merge branch '10.2' of github.com:MariaDB/server into bb-10.2-mariarocks
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | mysql-test/r/range.result | 674 | ||||
-rw-r--r-- | mysql-test/r/range_mrr_icp.result | 684 | ||||
-rw-r--r-- | mysql-test/t/range.test | 192 | ||||
-rw-r--r-- | plugin/aws_key_management/CMakeLists.txt | 51 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 3 | ||||
-rw-r--r-- | sql/item_row.h | 7 | ||||
-rw-r--r-- | sql/opt_range.cc | 217 | ||||
-rw-r--r-- | sql/sql_select.cc | 58 | ||||
-rw-r--r-- | storage/innobase/btr/btr0scrub.cc | 35 | ||||
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 4 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 43 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.h | 31 | ||||
-rw-r--r-- | storage/xtradb/btr/btr0scrub.cc | 35 | ||||
-rw-r--r-- | storage/xtradb/buf/buf0buf.cc | 10 | ||||
-rw-r--r-- | storage/xtradb/fil/fil0fil.cc | 52 | ||||
-rw-r--r-- | storage/xtradb/include/fil0fil.h | 17 |
17 files changed, 1965 insertions, 151 deletions
diff --git a/.gitignore b/.gitignore index 366842b24be..469aa0d894b 100644 --- a/.gitignore +++ b/.gitignore @@ -97,6 +97,9 @@ pcre/pcre_chartables.c pcre/pcregrep pcre/pcretest 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/make_binary_distribution scripts/msql2mysql diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 5027fffe047..28f5cf635d0 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -2332,3 +2332,677 @@ DROP TABLE t1; # # 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 +# diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index 7d009070150..f2860aaab76 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -2334,4 +2334,688 @@ DROP TABLE t1; # # 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; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 30f4419bd7e..ab951809b7a 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1857,3 +1857,195 @@ DROP TABLE t1; --echo # --echo # End of 10.1 tests --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 # + diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index d83c4830183..66b8074406f 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -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_KMS NAMES aws-cpp-sdk-kms PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") 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) - # AWS C++ SDK installed +IF(AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND AWS_CPP_SDK_INCLUDE_DIR) + # AWS C++ SDK installed + INCLUDE_DIRECTORIES(${AWS_CPP_SDK_INCLUDE_DIR}) SET(AWS_SDK_LIBS ${AWS_CPP_SDK_CORE} ${AWS_CPP_SDK_KMS}) ELSE() 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}) 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 ) ExternalProject_Add( aws_sdk_cpp GIT_REPOSITORY "https://github.com/awslabs/aws-sdk-cpp.git" GIT_TAG "1.0.8" UPDATE_COMMAND "" - SOURCE_DIR "${CMAKE_BINARY_DIR}/aws-sdk-cpp" - CMAKE_ARGS + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/aws-sdk-cpp" + ${byproducts} + CMAKE_ARGS -DBUILD_ONLY=kms -DBUILD_SHARED_LIBS=OFF -DFORCE_SHARED_CRT=OFF @@ -111,34 +126,28 @@ ELSE() "-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} ${PIC_FLAG}" "-DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL} ${PIC_FLAG}" ${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 "" ) 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") # Need whole-archive , otherwise static libraries are not linked SET(AWS_SDK_LIBS -Wl,--whole-archive ${AWS_SDK_LIBS} -Wl,--no-whole-archive) ENDIF() 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() ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized 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 - LINK_LIBRARIES ${AWS_SDK_LIBS} + LINK_LIBRARIES ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES} COMPONENT aws-key-management) + + diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1a2cc3a6c81..9c277220771 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1662,6 +1662,7 @@ public: void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables); 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) { /* @@ -1714,6 +1715,7 @@ public: cmp_item *make_same(); void store_value_by_template(THD *thd, cmp_item *tmpl, Item *); 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); friend void Item_func_in::fix_length_and_dec(); Item_result result_type() { return ROW_RESULT; } + cmp_item *get_cmp_item() { return &tmp; } }; /* Functions used by where clause */ diff --git a/sql/item_row.h b/sql/item_row.h index bbfebb56010..26468336dc8 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -119,6 +119,13 @@ public: bool check_cols(uint c); bool null_inside() { return with_null; }; 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; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_row>(thd, mem_root, this); } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6d088cad91e..d5de96b860a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7211,6 +7211,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 SYNOPSIS @@ -7544,12 +7743,22 @@ SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) if (const_item()) 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); - Item_field *field= (Item_field*) (key_item()->real_item()); - SEL_TREE *tree= get_full_func_mm_tree(param, field, NULL); + } DBUG_RETURN(tree); -} +} SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 987af7a3254..6e355ef58f5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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 usable_tables Tables which can be used for key optimization @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 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, KEY_FIELD **key_fields,uint and_level, Item_bool_func *cond, 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; if (eq_func && @@ -4751,7 +4754,15 @@ add_key_field(JOIN *join, bool optimizable=0; 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; if (!(value_used_tables & (field->table->map | RAND_TABLE_BIT))) optimizable=1; @@ -4789,7 +4800,15 @@ add_key_field(JOIN *join, bool is_const=1; 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; } if (is_const) @@ -4856,12 +4875,14 @@ add_key_field(JOIN *join, @param key_fields Pointer to add key, if usable @param and_level And level, to be stored in KEY_FIELD @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 value Value used for comparison with field - Is NULL for BETWEEN and IN + @param value Value used for comparison with field_item + @param num_values Number of values[] that we are comparing against @param usable_tables Tables which can be used for key optimization @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 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, bool eq_func, Item **val, 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; 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(); 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, 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, 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); + } + } + } + } diff --git a/storage/innobase/btr/btr0scrub.cc b/storage/innobase/btr/btr0scrub.cc index 4cb46dd415f..0d59481c4b5 100644 --- a/storage/innobase/btr/btr0scrub.cc +++ b/storage/innobase/btr/btr0scrub.cc @@ -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 * is closing, and then instead give up */ - if (lock_to_close_table == false) { - fil_space_t* space = fil_space_acquire(space_id); - if (!space || space->stop_new_ops) { - if (space) { - fil_space_release(space); - } + if (lock_to_close_table) { + } else if (fil_space_t* space = fil_space_acquire(space_id)) { + bool stopping = space->is_stopping(); + fil_space_release(space); + if (stopping) { return false; } - fil_space_release(space); + } else { + return false; } os_thread_sleep(250000); @@ -206,18 +206,15 @@ btr_scrub_table_close_for_thread( return; } - fil_space_t* space = fil_space_acquire(scrub_data->space); - - /* If tablespace is not marked as stopping perform - the actual close. */ - if (space && !space->is_stopping()) { - mutex_enter(&dict_sys->mutex); - /* perform the actual closing */ - btr_scrub_table_close(scrub_data->current_table); - mutex_exit(&dict_sys->mutex); - } - - if (space) { + if (fil_space_t* space = fil_space_acquire(scrub_data->space)) { + /* If tablespace is not marked as stopping perform + the actual close. */ + if (!space->is_stopping()) { + mutex_enter(&dict_sys->mutex); + /* perform the actual closing */ + btr_scrub_table_close(scrub_data->current_table); + mutex_exit(&dict_sys->mutex); + } fil_space_release(space); } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 11fe77d75de..a6ed277a90e 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -7535,12 +7535,12 @@ buf_page_decrypt_after_read(buf_page_t* bpage) return (true); } - FilSpace space(bpage->id.space()); + FilSpace space(bpage->id.space(), true); /* Page is encrypted if encryption information is found from tablespace and page contains used key_version. This is true also for pages first compressed and then encrypted. */ - if (!space()->crypt_data) { + if (!space() || !space()->crypt_data) { key_version = 0; } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index b38899e6de4..06ec31a7ed4 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2268,12 +2268,13 @@ Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID @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 fil_space_t* -fil_space_acquire_low( - ulint id, - bool silent) +fil_space_acquire_low(ulint id, bool silent, bool for_io = false) { fil_space_t* space; @@ -2286,7 +2287,7 @@ fil_space_acquire_low( ib::warn() << "Trying to access missing" " tablespace " << id; } - } else if (space->stop_new_ops || space->is_being_truncated) { + } else if (!for_io && space->is_stopping()) { space = NULL; } else { space->n_pending_ops++; @@ -2301,22 +2302,24 @@ fil_space_acquire_low( Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io) { - return(fil_space_acquire_low(id, false)); + return(fil_space_acquire_low(id, false, for_io)); } /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) { return(fil_space_acquire_low(id, true)); } @@ -2324,8 +2327,7 @@ fil_space_acquire_silent( /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space) +fil_space_release(fil_space_t* space) { mutex_enter(&fil_system->mutex); 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 (space->purpose != FIL_TYPE_TEMPORARY - && !space->stop_new_ops - && !space->is_being_truncated) { + && !space->is_stopping()) { fil_flush_low(space); } } @@ -5524,8 +5525,7 @@ fil_flush_file_spaces( space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { if (space->purpose == purpose - && !space->stop_new_ops - && !space->is_being_truncated) { + && !space->is_stopping()) { 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. @retval NULL if this was the last*/ fil_space_t* -fil_space_next( - fil_space_t* prev_space) +fil_space_next(fil_space_t* prev_space) { fil_space_t* space=prev_space; @@ -6725,8 +6724,8 @@ fil_space_next( fil_ibd_create(), or dropped, or !tablespace. */ while (space != NULL && (UT_LIST_GET_LEN(space->chain) == 0 - || space->stop_new_ops - || space->purpose != FIL_TYPE_TABLESPACE)) { + || space->is_stopping() + || space->purpose != FIL_TYPE_TABLESPACE)) { space = UT_LIST_GET_NEXT(space_list, space); } diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index abd9ff9a9ed..e63550f26ff 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -735,27 +735,28 @@ MY_ATTRIBUTE((warn_unused_result)); Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io = false) MY_ATTRIBUTE((warn_unused_result)); /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) MY_ATTRIBUTE((warn_unused_result)); /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space); +fil_space_release(fil_space_t* space); /** Return the next fil_space_t. Once started, the caller must keep calling this until it returns NULL. @@ -792,17 +793,19 @@ public: FilSpace() : m_space(NULL) {} /** Constructor: Look up the tablespace and increment the - referece count if found. - @param[in] space_id tablespace ID */ - explicit FilSpace(ulint space_id) - : m_space(fil_space_acquire(space_id)) {} + reference count if found. + @param[in] space_id tablespace ID + @param[in] for_io whether to look up the tablespace + 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() has already been done for the fil_space_t. The caller must assign NULL if it calls fil_space_release(). @param[in] space tablespace to assign */ - class FilSpace& operator=( - fil_space_t* space) + class FilSpace& operator=(fil_space_t* space) { /* fil_space_acquire() must have been invoked. */ ut_ad(space == NULL || space->n_pending_ops > 0); diff --git a/storage/xtradb/btr/btr0scrub.cc b/storage/xtradb/btr/btr0scrub.cc index 560d2ece6c0..e9434c9f778 100644 --- a/storage/xtradb/btr/btr0scrub.cc +++ b/storage/xtradb/btr/btr0scrub.cc @@ -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 * is closing, and then instead give up */ - if (lock_to_close_table == false) { - fil_space_t* space = fil_space_acquire(space_id); - if (!space || space->stop_new_ops) { - if (space) { - fil_space_release(space); - } + if (lock_to_close_table) { + } else if (fil_space_t* space = fil_space_acquire(space_id)) { + bool stopping = space->is_stopping(); + fil_space_release(space); + if (stopping) { return false; } - fil_space_release(space); + } else { + return false; } os_thread_sleep(250000); @@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread( return; } - fil_space_t* space = fil_space_acquire(scrub_data->space); - - /* If tablespace is not marked as stopping perform - the actual close. */ - if (space && !space->is_stopping()) { - mutex_enter(&dict_sys->mutex); - /* perform the actual closing */ - btr_scrub_table_close(scrub_data->current_table); - mutex_exit(&dict_sys->mutex); - } - - if (space) { + if (fil_space_t* space = fil_space_acquire(scrub_data->space)) { + /* If tablespace is not marked as stopping perform + the actual close. */ + if (!space->is_stopping()) { + mutex_enter(&dict_sys->mutex); + /* perform the actual closing */ + btr_scrub_table_close(scrub_data->current_table); + mutex_exit(&dict_sys->mutex); + } fil_space_release(space); } diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index c9a3f6aa6ec..70cd9610b18 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -6413,14 +6413,12 @@ buf_page_decrypt_after_read( return (true); } - fil_space_t* space = fil_space_acquire(bpage->space); - - fil_space_crypt_t* crypt_data = space->crypt_data; + fil_space_t* space = fil_space_acquire(bpage->space, true); /* Page is encrypted if encryption information is found from tablespace and page contains used key_version. This is true also for pages first compressed and then encrypted. */ - if (!crypt_data) { + if (!space || !space->crypt_data) { 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); } diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index a116bfad99d..e7244d719c8 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -6389,16 +6389,12 @@ fil_flush( { mutex_enter(&fil_system->mutex); - fil_space_t* space = fil_space_get_by_id(space_id); - - if (!space || space->stop_new_ops) { - mutex_exit(&fil_system->mutex); - - return; + if (fil_space_t* space = fil_space_get_by_id(space_id)) { + if (!space->is_stopping()) { + fil_flush_low(space); + } } - fil_flush_low(space); - mutex_exit(&fil_system->mutex); } @@ -6438,8 +6434,7 @@ fil_flush_file_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; } } @@ -7388,12 +7383,13 @@ Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID @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 fil_space_t* -fil_space_acquire_low( - ulint id, - bool silent) +fil_space_acquire_low(ulint id, bool silent, bool for_io = false) { fil_space_t* space; @@ -7407,7 +7403,7 @@ fil_space_acquire_low( " tablespace " ULINTPF ".", id); ut_error; } - } else if (space->stop_new_ops) { + } else if (!for_io && space->is_stopping()) { space = NULL; } else { space->n_pending_ops++; @@ -7422,22 +7418,24 @@ fil_space_acquire_low( Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io) { - return(fil_space_acquire_low(id, false)); + return(fil_space_acquire_low(id, false, for_io)); } /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) { return(fil_space_acquire_low(id, true)); } @@ -7445,8 +7443,7 @@ fil_space_acquire_silent( /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space) +fil_space_release(fil_space_t* space) { mutex_enter(&fil_system->mutex); 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. @retval NULL if this was the last*/ fil_space_t* -fil_space_next( - fil_space_t* prev_space) +fil_space_next(fil_space_t* prev_space) { fil_space_t* space=prev_space; @@ -7488,8 +7484,8 @@ fil_space_next( fil_ibd_create(), or dropped, or !tablespace. */ while (space != NULL && (UT_LIST_GET_LEN(space->chain) == 0 - || space->stop_new_ops - || space->purpose != FIL_TABLESPACE)) { + || space->is_stopping() + || space->purpose != FIL_TABLESPACE)) { space = UT_LIST_GET_NEXT(space_list, space); } diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index b80df057351..698039afede 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -650,27 +650,28 @@ fil_write_flushed_lsn_to_data_files( Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io = false) MY_ATTRIBUTE((warn_unused_result)); /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @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_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) MY_ATTRIBUTE((warn_unused_result)); /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space); +fil_space_release(fil_space_t* space); /** Return the next fil_space_t. Once started, the caller must keep calling this until it returns NULL. |