Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
deb3b9a1
Commit
deb3b9a1
authored
May 25, 2011
by
Igor Babaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Downported InnoDB support of Index Condition Pushdown from MySQL-5.6 code line.
parent
7fc2d46a
Changes
25
Show whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
1165 additions
and
587 deletions
+1165
-587
include/my_handler.h
include/my_handler.h
+3
-1
mysql-test/include/icp_tests.inc
mysql-test/include/icp_tests.inc
+60
-0
mysql-test/r/index_merge_innodb.result
mysql-test/r/index_merge_innodb.result
+1
-1
mysql-test/r/innodb.result
mysql-test/r/innodb.result
+1
-1
mysql-test/r/innodb_icp.result
mysql-test/r/innodb_icp.result
+59
-0
mysql-test/r/maria_icp.result
mysql-test/r/maria_icp.result
+65
-0
mysql-test/r/myisam_icp.result
mysql-test/r/myisam_icp.result
+65
-0
mysql-test/r/myisam_mrr.result
mysql-test/r/myisam_mrr.result
+1
-1
mysql-test/r/null_key.result
mysql-test/r/null_key.result
+10
-10
mysql-test/r/order_by.result
mysql-test/r/order_by.result
+1
-1
mysql-test/r/range_vs_index_merge_innodb.result
mysql-test/r/range_vs_index_merge_innodb.result
+13
-13
mysql-test/suite/innodb/r/innodb.result
mysql-test/suite/innodb/r/innodb.result
+1
-1
mysql-test/suite/innodb/r/innodb_lock_wait_timeout_1.result
mysql-test/suite/innodb/r/innodb_lock_wait_timeout_1.result
+2
-2
mysql-test/suite/innodb/r/innodb_mysql.result
mysql-test/suite/innodb/r/innodb_mysql.result
+2
-2
mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result
...t/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result
+2
-2
mysql-test/suite/pbxt/r/null_key.result
mysql-test/suite/pbxt/r/null_key.result
+10
-10
sql/opt_index_cond_pushdown.cc
sql/opt_index_cond_pushdown.cc
+38
-27
storage/xtradb/dict/dict0dict.c
storage/xtradb/dict/dict0dict.c
+8
-5
storage/xtradb/handler/ha_innodb.cc
storage/xtradb/handler/ha_innodb.cc
+376
-228
storage/xtradb/handler/ha_innodb.h
storage/xtradb/handler/ha_innodb.h
+69
-16
storage/xtradb/include/dict0dict.h
storage/xtradb/include/dict0dict.h
+12
-0
storage/xtradb/include/dict0dict.ic
storage/xtradb/include/dict0dict.ic
+14
-0
storage/xtradb/include/ha_prototypes.h
storage/xtradb/include/ha_prototypes.h
+9
-0
storage/xtradb/include/row0mysql.h
storage/xtradb/include/row0mysql.h
+11
-18
storage/xtradb/row/row0sel.c
storage/xtradb/row/row0sel.c
+332
-248
No files found.
include/my_handler.h
View file @
deb3b9a1
...
@@ -135,6 +135,7 @@ extern void my_handler_error_unregister(void);
...
@@ -135,6 +135,7 @@ extern void my_handler_error_unregister(void);
if we're scanning "t.key BETWEEN 10 AND 20" and got a
if we're scanning "t.key BETWEEN 10 AND 20" and got a
"t.key=21" tuple (the engine should stop scanning and return
"t.key=21" tuple (the engine should stop scanning and return
HA_ERR_END_OF_FILE right away).
HA_ERR_END_OF_FILE right away).
3=ICP_ABORTED_BY_USER
-1= ICP_ERROR - Reserved for internal errors in engines. Should not be
-1= ICP_ERROR - Reserved for internal errors in engines. Should not be
returned by index_cond_func_xxx
returned by index_cond_func_xxx
...
@@ -144,7 +145,8 @@ typedef enum icp_result {
...
@@ -144,7 +145,8 @@ typedef enum icp_result {
ICP_ERROR
=-
1
,
ICP_ERROR
=-
1
,
ICP_NO_MATCH
=
0
,
ICP_NO_MATCH
=
0
,
ICP_MATCH
=
1
,
ICP_MATCH
=
1
,
ICP_OUT_OF_RANGE
=
2
ICP_OUT_OF_RANGE
=
2
,
ICP_ABORTED_BY_USER
=
3
,
}
ICP_RESULT
;
}
ICP_RESULT
;
...
...
mysql-test/include/icp_tests.inc
View file @
deb3b9a1
...
@@ -225,3 +225,63 @@ SELECT COUNT(*) FROM t3;
...
@@ -225,3 +225,63 @@ SELECT COUNT(*) FROM t3;
DROP
PROCEDURE
insert_data
;
DROP
PROCEDURE
insert_data
;
DROP
TABLE
t1
,
t2
,
t3
;
DROP
TABLE
t1
,
t2
,
t3
;
--
echo
#
--
echo
# Bug#57372 "Multi-table updates and deletes fail when running with ICP
--
echo
# against InnoDB"
--
echo
#
CREATE
TABLE
t1
(
a
INT
KEY
,
b
INT
);
CREATE
TABLE
t2
(
a
INT
KEY
,
b
INT
);
INSERT
INTO
t1
VALUES
(
1
,
101
),
(
2
,
102
),
(
3
,
103
),
(
4
,
104
),
(
5
,
105
);
INSERT
INTO
t2
VALUES
(
1
,
1
),
(
2
,
2
),
(
3
,
3
),
(
4
,
4
),
(
5
,
5
);
UPDATE
t1
,
t2
SET
t1
.
a
=
t1
.
a
+
100
,
t2
.
b
=
t1
.
a
+
10
WHERE
t1
.
a
BETWEEN
2
AND
4
AND
t2
.
a
=
t1
.
b
-
100
;
--
sorted_result
SELECT
*
FROM
t1
;
--
sorted_result
SELECT
*
FROM
t2
;
DROP
TABLE
t1
,
t2
;
--
echo
#
--
echo
# Bug#59259 "Incorrect rows returned for a correlated subquery
--
echo
# when ICP is on"
--
echo
#
CREATE
TABLE
t1
(
pk
INTEGER
PRIMARY
KEY
,
i
INTEGER
NOT
NULL
)
ENGINE
=
InnoDB
;
INSERT
INTO
t1
VALUES
(
11
,
0
);
INSERT
INTO
t1
VALUES
(
12
,
5
);
INSERT
INTO
t1
VALUES
(
15
,
0
);
CREATE
TABLE
t2
(
pk
INTEGER
PRIMARY
KEY
,
i
INTEGER
NOT
NULL
)
ENGINE
=
InnoDB
;
INSERT
INTO
t2
VALUES
(
11
,
1
);
INSERT
INTO
t2
VALUES
(
12
,
2
);
INSERT
INTO
t2
VALUES
(
15
,
4
);
set
@
save_optimizer_switch
=
@@
optimizer_switch
;
set
optimizer_switch
=
'semijoin=off'
;
EXPLAIN
SELECT
*
FROM
t1
WHERE
pk
IN
(
SELECT
it
.
pk
FROM
t2
JOIN
t2
AS
it
ON
it
.
i
=
it
.
i
WHERE
it
.
pk
-
t1
.
i
<
10
);
SELECT
*
FROM
t1
WHERE
pk
IN
(
SELECT
it
.
pk
FROM
t2
JOIN
t2
AS
it
ON
it
.
i
=
it
.
i
WHERE
it
.
pk
-
t1
.
i
<
10
);
set
optimizer_switch
=@
save_optimizer_switch
;
DROP
TABLE
t1
,
t2
;
mysql-test/r/index_merge_innodb.result
View file @
deb3b9a1
...
@@ -549,7 +549,7 @@ primary key (pk1, pk2)
...
@@ -549,7 +549,7 @@ primary key (pk1, pk2)
);
);
explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY,key1 PRIMARY 8 NULL 9 Using where
1 SIMPLE t1 range PRIMARY,key1 PRIMARY 8 NULL 9 Using
index condition; Using
where
select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
pk1 pk2 key1 key2 pktail1ok pktail2ok pktail3bad pktail4bad pktail5bad pk2copy badkey filler1 filler2
pk1 pk2 key1 key2 pktail1ok pktail2ok pktail3bad pktail4bad pktail5bad pk2copy badkey filler1 filler2
1 10 0 0 0 0 0 0 0 10 0 filler-data-10 filler2
1 10 0 0 0 0 0 0 0 10 0 filler-data-10 filler2
...
...
mysql-test/r/innodb.result
View file @
deb3b9a1
...
@@ -778,7 +778,7 @@ create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h
...
@@ -778,7 +778,7 @@ create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h
insert into t1 values (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
insert into t1 values (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
explain select * from t1 where a > 0 and a < 50;
explain select * from t1 where a > 0 and a < 50;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL # Using
where
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL # Using
index condition
drop table t1;
drop table t1;
create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb;
create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb;
insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
...
...
mysql-test/r/innodb_icp.result
View file @
deb3b9a1
...
@@ -200,4 +200,63 @@ COUNT(*)
...
@@ -200,4 +200,63 @@ COUNT(*)
12
12
DROP PROCEDURE insert_data;
DROP PROCEDURE insert_data;
DROP TABLE t1, t2, t3;
DROP TABLE t1, t2, t3;
#
# Bug#57372 "Multi-table updates and deletes fail when running with ICP
# against InnoDB"
#
CREATE TABLE t1 (
a INT KEY,
b INT
);
CREATE TABLE t2 (
a INT KEY,
b INT
);
INSERT INTO t1 VALUES (1, 101), (2, 102), (3, 103), (4, 104), (5, 105);
INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
UPDATE t1, t2
SET t1.a = t1.a + 100, t2.b = t1.a + 10
WHERE t1.a BETWEEN 2 AND 4 AND t2.a = t1.b - 100;
SELECT * FROM t1;
a b
1 101
102 102
103 103
104 104
5 105
SELECT * FROM t2;
a b
1 1
2 12
3 13
4 14
5 5
DROP TABLE t1, t2;
#
# Bug#59259 "Incorrect rows returned for a correlated subquery
# when ICP is on"
#
CREATE TABLE t1 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES (11,0);
INSERT INTO t1 VALUES (12,5);
INSERT INTO t1 VALUES (15,0);
CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL) ENGINE=InnoDB;
INSERT INTO t2 VALUES (11,1);
INSERT INTO t2 VALUES (12,2);
INSERT INTO t2 VALUES (15,4);
set @save_optimizer_switch= @@optimizer_switch;
set optimizer_switch='semijoin=off';
EXPLAIN
SELECT * FROM t1
WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index
2 DEPENDENT SUBQUERY it eq_ref PRIMARY PRIMARY 4 func 1 Using index condition
SELECT * FROM t1
WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10);
pk i
12 5
set optimizer_switch=@save_optimizer_switch;
DROP TABLE t1, t2;
set storage_engine= @save_storage_engine;
set storage_engine= @save_storage_engine;
mysql-test/r/maria_icp.result
View file @
deb3b9a1
...
@@ -200,4 +200,69 @@ COUNT(*)
...
@@ -200,4 +200,69 @@ COUNT(*)
12
12
DROP PROCEDURE insert_data;
DROP PROCEDURE insert_data;
DROP TABLE t1, t2, t3;
DROP TABLE t1, t2, t3;
#
# Bug#57372 "Multi-table updates and deletes fail when running with ICP
# against InnoDB"
#
CREATE TABLE t1 (
a INT KEY,
b INT
);
CREATE TABLE t2 (
a INT KEY,
b INT
);
INSERT INTO t1 VALUES (1, 101), (2, 102), (3, 103), (4, 104), (5, 105);
INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
UPDATE t1, t2
SET t1.a = t1.a + 100, t2.b = t1.a + 10
WHERE t1.a BETWEEN 2 AND 4 AND t2.a = t1.b - 100;
SELECT * FROM t1;
a b
1 101
102 102
103 103
104 104
5 105
SELECT * FROM t2;
a b
1 1
2 12
3 13
4 14
5 5
DROP TABLE t1, t2;
#
# Bug#59259 "Incorrect rows returned for a correlated subquery
# when ICP is on"
#
CREATE TABLE t1 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL) ENGINE=InnoDB;
Warnings:
Warning 1286 Unknown table engine 'InnoDB'
Warning 1266 Using storage engine Aria for table 't1'
INSERT INTO t1 VALUES (11,0);
INSERT INTO t1 VALUES (12,5);
INSERT INTO t1 VALUES (15,0);
CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL) ENGINE=InnoDB;
Warnings:
Warning 1286 Unknown table engine 'InnoDB'
Warning 1266 Using storage engine Aria for table 't2'
INSERT INTO t2 VALUES (11,1);
INSERT INTO t2 VALUES (12,2);
INSERT INTO t2 VALUES (15,4);
set @save_optimizer_switch= @@optimizer_switch;
set optimizer_switch='semijoin=off';
EXPLAIN
SELECT * FROM t1
WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index
2 DEPENDENT SUBQUERY it eq_ref PRIMARY PRIMARY 4 func 1 Using index condition
SELECT * FROM t1
WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10);
pk i
12 5
set optimizer_switch=@save_optimizer_switch;
DROP TABLE t1, t2;
set storage_engine= @save_storage_engine;
set storage_engine= @save_storage_engine;
mysql-test/r/myisam_icp.result
View file @
deb3b9a1
...
@@ -198,4 +198,69 @@ COUNT(*)
...
@@ -198,4 +198,69 @@ COUNT(*)
12
12
DROP PROCEDURE insert_data;
DROP PROCEDURE insert_data;
DROP TABLE t1, t2, t3;
DROP TABLE t1, t2, t3;
#
# Bug#57372 "Multi-table updates and deletes fail when running with ICP
# against InnoDB"
#
CREATE TABLE t1 (
a INT KEY,
b INT
);
CREATE TABLE t2 (
a INT KEY,
b INT
);
INSERT INTO t1 VALUES (1, 101), (2, 102), (3, 103), (4, 104), (5, 105);
INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
UPDATE t1, t2
SET t1.a = t1.a + 100, t2.b = t1.a + 10
WHERE t1.a BETWEEN 2 AND 4 AND t2.a = t1.b - 100;
SELECT * FROM t1;
a b
1 101
102 102
103 103
104 104
5 105
SELECT * FROM t2;
a b
1 1
2 12
3 13
4 14
5 5
DROP TABLE t1, t2;
#
# Bug#59259 "Incorrect rows returned for a correlated subquery
# when ICP is on"
#
CREATE TABLE t1 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL) ENGINE=InnoDB;
Warnings:
Warning 1286 Unknown table engine 'InnoDB'
Warning 1266 Using storage engine MyISAM for table 't1'
INSERT INTO t1 VALUES (11,0);
INSERT INTO t1 VALUES (12,5);
INSERT INTO t1 VALUES (15,0);
CREATE TABLE t2 (pk INTEGER PRIMARY KEY, i INTEGER NOT NULL) ENGINE=InnoDB;
Warnings:
Warning 1286 Unknown table engine 'InnoDB'
Warning 1266 Using storage engine MyISAM for table 't2'
INSERT INTO t2 VALUES (11,1);
INSERT INTO t2 VALUES (12,2);
INSERT INTO t2 VALUES (15,4);
set @save_optimizer_switch= @@optimizer_switch;
set optimizer_switch='semijoin=off';
EXPLAIN
SELECT * FROM t1
WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
2 DEPENDENT SUBQUERY t2 index NULL PRIMARY 4 NULL 3 Using index
2 DEPENDENT SUBQUERY it eq_ref PRIMARY PRIMARY 4 func 1 Using index condition
SELECT * FROM t1
WHERE pk IN (SELECT it.pk FROM t2 JOIN t2 AS it ON it.i=it.i WHERE it.pk-t1.i<10);
pk i
12 5
set optimizer_switch=@save_optimizer_switch;
DROP TABLE t1, t2;
drop table if exists t0, t1, t1i, t1m;
drop table if exists t0, t1, t1i, t1m;
mysql-test/r/myisam_mrr.result
View file @
deb3b9a1
...
@@ -363,7 +363,7 @@ update t1 set b=repeat(char(65+a), 20) where a < 25;
...
@@ -363,7 +363,7 @@ update t1 set b=repeat(char(65+a), 20) where a < 25;
This must show range + using index condition:
This must show range + using index condition:
explain select * from t1 where a < 10 and b = repeat(char(65+a), 20);
explain select * from t1 where a < 10 and b = repeat(char(65+a), 20);
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 19 Using where
1 SIMPLE t1 range a a 5 NULL 19 Using
index condition; Using
where
select * from t1 where a < 10 and b = repeat(char(65+a), 20);
select * from t1 where a < 10 and b = repeat(char(65+a), 20);
a b filler
a b filler
0 AAAAAAAAAAAAAAAAAAAA filler
0 AAAAAAAAAAAAAAAAAAAA filler
...
...
mysql-test/r/null_key.result
View file @
deb3b9a1
...
@@ -76,13 +76,13 @@ insert into t2 select * from t1;
...
@@ -76,13 +76,13 @@ insert into t2 select * from t1;
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
explain select * from t1 where a is null and b = 2;
explain select * from t1 where a is null and b = 2;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a is null and b = 2 and c=0;
explain select * from t1 where a is null and b = 2 and c=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a is null and b = 7 and c=0;
explain select * from t1 where a is null and b = 7 and c=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a=2 and b = 2;
explain select * from t1 where a=2 and b = 2;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 1 Using where
1 SIMPLE t1 ref a,b a 5 const 1 Using where
...
@@ -91,25 +91,25 @@ id select_type table type possible_keys key key_len ref rows Extra
...
@@ -91,25 +91,25 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where
explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 and c=0 limit 3;
explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 and c=0 limit 3;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a,b a 5 NULL 5 Using where
1 SIMPLE t1 range a,b a 5 NULL 5 Using
index condition; Using
where
explain select * from t1 where (a is null or a = 7) and b=7 and c=0;
explain select * from t1 where (a is null or a = 7) and b=7 and c=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where
1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using
index condition; Using
where
explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a > 1 and a < 3 limit 1;
explain select * from t1 where a > 1 and a < 3 limit 1;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 1 Using
where
1 SIMPLE t1 range a a 5 NULL 1 Using
index condition
explain select * from t1 where a is null and b=7 or a > 1 and a < 3 limit 1;
explain select * from t1 where a is null and b=7 or a > 1 and a < 3 limit 1;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a,b a 5 NULL 4 Using where
1 SIMPLE t1 range a,b a 5 NULL 4 Using
index condition; Using
where
explain select * from t1 where a > 8 and a < 9;
explain select * from t1 where a > 8 and a < 9;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 1 Using
where
1 SIMPLE t1 range a a 5 NULL 1 Using
index condition
explain select * from t1 where b like "6%";
explain select * from t1 where b like "6%";
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range b b 12 NULL 1 Using where
1 SIMPLE t1 range b b 12 NULL 1 Using where
...
...
mysql-test/r/order_by.result
View file @
deb3b9a1
...
@@ -614,7 +614,7 @@ id select_type table type possible_keys key key_len ref rows Extra
...
@@ -614,7 +614,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range FieldKey FieldKey 38 NULL 4 Using index condition; Using MRR; Using filesort
1 SIMPLE t1 range FieldKey FieldKey 38 NULL 4 Using index condition; Using MRR; Using filesort
EXPLAIN SELECT * FROM t1 IGNORE INDEX (FieldKey, LongField) WHERE FieldKey > '2' ORDER BY LongVal;
EXPLAIN SELECT * FROM t1 IGNORE INDEX (FieldKey, LongField) WHERE FieldKey > '2' ORDER BY LongVal;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range StringField StringField 38 NULL 4 Using
where
; Using filesort
1 SIMPLE t1 range StringField StringField 38 NULL 4 Using
index condition
; Using filesort
SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal;
SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal;
FieldKey LongVal StringVal
FieldKey LongVal StringVal
3 1 2
3 1 2
...
...
mysql-test/r/range_vs_index_merge_innodb.result
View file @
deb3b9a1
...
@@ -328,15 +328,15 @@ ID Name Country Population
...
@@ -328,15 +328,15 @@ ID Name Country Population
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE (ID < 10) OR (ID BETWEEN 100 AND 110);
SELECT * FROM City WHERE (ID < 10) OR (ID BETWEEN 100 AND 110);
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 20 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 20 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE (ID < 200) OR (ID BETWEEN 100 AND 200);
SELECT * FROM City WHERE (ID < 200) OR (ID BETWEEN 100 AND 200);
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 199 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 199 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE (ID < 600) OR (ID BETWEEN 900 AND 1500);
SELECT * FROM City WHERE (ID < 600) OR (ID BETWEEN 900 AND 1500);
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 2006 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 2006 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE Country > 'A' AND Country < 'ARG';
SELECT * FROM City WHERE Country > 'A' AND Country < 'ARG';
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
...
@@ -355,7 +355,7 @@ WHERE ((ID < 10) AND (Name LIKE 'H%' OR (Country > 'A' AND Country < 'ARG')))
...
@@ -355,7 +355,7 @@ WHERE ((ID < 10) AND (Name LIKE 'H%' OR (Country > 'A' AND Country < 'ARG')))
OR ((ID BETWEEN 100 AND 110) AND
OR ((ID BETWEEN 100 AND 110) AND
(Name LIKE 'P%' OR (Population > 103000 AND Population < 104000)));
(Name LIKE 'P%' OR (Population > 103000 AND Population < 104000)));
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY,Population,Country,Name PRIMARY 4 NULL 20 Using where
1 SIMPLE City range PRIMARY,Population,Country,Name PRIMARY 4 NULL 20 Using
index condition; Using
where
EXPLAIN
EXPLAIN
SELECT * FROM City
SELECT * FROM City
WHERE ((ID < 800) AND (Name LIKE 'Ha%' OR (Country > 'A' AND Country < 'ARG')))
WHERE ((ID < 800) AND (Name LIKE 'Ha%' OR (Country > 'A' AND Country < 'ARG')))
...
@@ -369,7 +369,7 @@ WHERE ((ID < 200) AND (Name LIKE 'Ha%' OR (Country > 'A' AND Country < 'ARG')))
...
@@ -369,7 +369,7 @@ WHERE ((ID < 200) AND (Name LIKE 'Ha%' OR (Country > 'A' AND Country < 'ARG')))
OR ((ID BETWEEN 100 AND 200) AND
OR ((ID BETWEEN 100 AND 200) AND
(Name LIKE 'Pa%' OR (Population > 103000 AND Population < 104000)));
(Name LIKE 'Pa%' OR (Population > 103000 AND Population < 104000)));
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY,Population,Country,Name PRIMARY 4 NULL 199 Using where
1 SIMPLE City range PRIMARY,Population,Country,Name PRIMARY 4 NULL 199 Using
index condition; Using
where
SELECT * FROM City USE INDEX ()
SELECT * FROM City USE INDEX ()
WHERE ((ID < 10) AND (Name LIKE 'H%' OR (Country > 'A' AND Country < 'ARG')))
WHERE ((ID < 10) AND (Name LIKE 'H%' OR (Country > 'A' AND Country < 'ARG')))
OR ((ID BETWEEN 100 AND 110) AND
OR ((ID BETWEEN 100 AND 110) AND
...
@@ -601,11 +601,11 @@ id select_type table type possible_keys key key_len ref rows Extra
...
@@ -601,11 +601,11 @@ id select_type table type possible_keys key key_len ref rows Extra
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 3400 AND 3800;
SELECT * FROM City WHERE ID BETWEEN 3400 AND 3800;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 944 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 944 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 3790 AND 3800;
SELECT * FROM City WHERE ID BETWEEN 3790 AND 3800;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE Name LIKE 'P%';
SELECT * FROM City WHERE Name LIKE 'P%';
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
...
@@ -765,27 +765,27 @@ id select_type table type possible_keys key key_len ref rows Extra
...
@@ -765,27 +765,27 @@ id select_type table type possible_keys key key_len ref rows Extra
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 3790 AND 3800;
SELECT * FROM City WHERE ID BETWEEN 3790 AND 3800;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 4025 AND 4035;
SELECT * FROM City WHERE ID BETWEEN 4025 AND 4035;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 4028 AND 4032;
SELECT * FROM City WHERE ID BETWEEN 4028 AND 4032;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 5 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 5 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 3500 AND 3800;
SELECT * FROM City WHERE ID BETWEEN 3500 AND 3800;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 300 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 300 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 4000 AND 4300;
SELECT * FROM City WHERE ID BETWEEN 4000 AND 4300;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 80 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 80 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE ID BETWEEN 250 and 260 ;
SELECT * FROM City WHERE ID BETWEEN 250 and 260 ;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
where
1 SIMPLE City range PRIMARY PRIMARY 4 NULL 11 Using
index condition
EXPLAIN
EXPLAIN
SELECT * FROM City WHERE (Population > 101000 AND Population < 102000);
SELECT * FROM City WHERE (Population > 101000 AND Population < 102000);
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
...
...
mysql-test/suite/innodb/r/innodb.result
View file @
deb3b9a1
...
@@ -778,7 +778,7 @@ create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h
...
@@ -778,7 +778,7 @@ create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h
insert into t1 values (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
insert into t1 values (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
explain select * from t1 where a > 0 and a < 50;
explain select * from t1 where a > 0 and a < 50;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL # Using
where
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL # Using
index condition
drop table t1;
drop table t1;
create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb;
create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb;
insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
...
...
mysql-test/suite/innodb/r/innodb_lock_wait_timeout_1.result
View file @
deb3b9a1
...
@@ -119,7 +119,7 @@ key PRIMARY
...
@@ -119,7 +119,7 @@ key PRIMARY
key_len 4
key_len 4
ref t2.a
ref t2.a
rows 1
rows 1
Extra Using where
Extra Using
index condition; Using
where
id 2
id 2
select_type DERIVED
select_type DERIVED
table NULL
table NULL
...
@@ -323,7 +323,7 @@ key PRIMARY
...
@@ -323,7 +323,7 @@ key PRIMARY
key_len 4
key_len 4
ref t2.a
ref t2.a
rows 1
rows 1
Extra Using where
Extra Using
index condition; Using
where
id 2
id 2
select_type DERIVED
select_type DERIVED
table NULL
table NULL
...
...
mysql-test/suite/innodb/r/innodb_mysql.result
View file @
deb3b9a1
...
@@ -2766,7 +2766,7 @@ WHERE t2.i = t1.pk AND t1.pk BETWEEN 0 AND 224
...
@@ -2766,7 +2766,7 @@ WHERE t2.i = t1.pk AND t1.pk BETWEEN 0 AND 224
HAVING f > 7
HAVING f > 7
ORDER BY f;
ORDER BY f;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using filesort
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using
index condition; Using
where; Using filesort
1 SIMPLE t2 ref idx idx 5 test.t1.pk 1 Using index
1 SIMPLE t2 ref idx idx 5 test.t1.pk 1 Using index
SELECT t1 .i AS f FROM t1, t2
SELECT t1 .i AS f FROM t1, t2
WHERE t2.i = t1.pk AND t1.pk BETWEEN 0 AND 224
WHERE t2.i = t1.pk AND t1.pk BETWEEN 0 AND 224
...
@@ -2798,7 +2798,7 @@ SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.pk = t2.a
...
@@ -2798,7 +2798,7 @@ SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.pk = t2.a
WHERE t1.pk >= 6 HAVING t1.a<> 0 AND t1.a <> 11
WHERE t1.pk >= 6 HAVING t1.a<> 0 AND t1.a <> 11
ORDER BY t1.a;
ORDER BY t1.a;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using filesort
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using
index condition; Using
where; Using filesort
1 SIMPLE t2 ref a a 5 test.t1.pk 1 Using index
1 SIMPLE t2 ref a a 5 test.t1.pk 1 Using index
SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.pk = t2.a
SELECT t1.a FROM t1 LEFT JOIN t2 ON t1.pk = t2.a
WHERE t1.pk >= 6 HAVING t1.a<> 0 AND t1.a <> 11
WHERE t1.pk >= 6 HAVING t1.a<> 0 AND t1.a <> 11
...
...
mysql-test/suite/innodb_plugin/r/innodb_lock_wait_timeout_1.result
View file @
deb3b9a1
...
@@ -119,7 +119,7 @@ key PRIMARY
...
@@ -119,7 +119,7 @@ key PRIMARY
key_len 4
key_len 4
ref t2.a
ref t2.a
rows 1
rows 1
Extra Using where
Extra Using
index condition; Using
where
id 2
id 2
select_type DERIVED
select_type DERIVED
table NULL
table NULL
...
@@ -323,7 +323,7 @@ key PRIMARY
...
@@ -323,7 +323,7 @@ key PRIMARY
key_len 4
key_len 4
ref t2.a
ref t2.a
rows 1
rows 1
Extra Using where
Extra Using
index condition; Using
where
id 2
id 2
select_type DERIVED
select_type DERIVED
table NULL
table NULL
...
...
mysql-test/suite/pbxt/r/null_key.result
View file @
deb3b9a1
...
@@ -76,13 +76,13 @@ insert into t2 select * from t1;
...
@@ -76,13 +76,13 @@ insert into t2 select * from t1;
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
explain select * from t1 where a is null and b = 2;
explain select * from t1 where a is null and b = 2;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a is null and b = 2 and c=0;
explain select * from t1 where a is null and b = 2 and c=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a is null and b = 7 and c=0;
explain select * from t1 where a is null and b = 7 and c=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a=2 and b = 2;
explain select * from t1 where a=2 and b = 2;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 1 Using where
1 SIMPLE t1 ref a,b a 5 const 1 Using where
...
@@ -91,25 +91,25 @@ id select_type table type possible_keys key key_len ref rows Extra
...
@@ -91,25 +91,25 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where
explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 and c=0 limit 3;
explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 and c=0 limit 3;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a,b a 5 NULL 5 Using where
1 SIMPLE t1 range a,b a 5 NULL 5 Using
index condition; Using
where
explain select * from t1 where (a is null or a = 7) and b=7 and c=0;
explain select * from t1 where (a is null or a = 7) and b=7 and c=0;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where
1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using
index condition; Using
where
explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
1 SIMPLE t1 ref a,b a 5 const 3 Using
index condition; Using
where
explain select * from t1 where a > 1 and a < 3 limit 1;
explain select * from t1 where a > 1 and a < 3 limit 1;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 1 Using
where
1 SIMPLE t1 range a a 5 NULL 1 Using
index condition
explain select * from t1 where a is null and b=7 or a > 1 and a < 3 limit 1;
explain select * from t1 where a is null and b=7 or a > 1 and a < 3 limit 1;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a,b a 5 NULL 4 Using where
1 SIMPLE t1 range a,b a 5 NULL 4 Using
index condition; Using
where
explain select * from t1 where a > 8 and a < 9;
explain select * from t1 where a > 8 and a < 9;
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 1 Using
where
1 SIMPLE t1 range a a 5 NULL 1 Using
index condition
explain select * from t1 where b like "6%";
explain select * from t1 where b like "6%";
id select_type table type possible_keys key key_len ref rows Extra
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range b b 12 NULL 1 Using where
1 SIMPLE t1 range b b 12 NULL 1 Using where
...
...
sql/opt_index_cond_pushdown.cc
View file @
deb3b9a1
...
@@ -83,15 +83,44 @@ bool uses_index_fields_only(Item *item, TABLE *tbl, uint keyno,
...
@@ -83,15 +83,44 @@ bool uses_index_fields_only(Item *item, TABLE *tbl, uint keyno,
case
Item
:
:
FIELD_ITEM
:
case
Item
:
:
FIELD_ITEM
:
{
{
Item_field
*
item_field
=
(
Item_field
*
)
item
;
Item_field
*
item_field
=
(
Item_field
*
)
item
;
if
(
item_field
->
field
->
table
!=
tbl
)
Field
*
field
=
item_field
->
field
;
if
(
field
->
table
!=
tbl
)
return
TRUE
;
return
TRUE
;
/*
/*
The below is probably a repetition - the first part checks the
The below is probably a repetition - the first part checks the
other two, but let's play it safe:
other two, but let's play it safe:
*/
*/
return
item_field
->
field
->
part_of_key
.
is_set
(
keyno
)
&&
if
(
!
field
->
part_of_key
.
is_set
(
keyno
)
||
item_field
->
field
->
type
()
!=
MYSQL_TYPE_GEOMETRY
&&
field
->
type
()
==
MYSQL_TYPE_GEOMETRY
||
item_field
->
field
->
type
()
!=
MYSQL_TYPE_BLOB
;
field
->
type
()
==
MYSQL_TYPE_BLOB
)
return
FALSE
;
KEY
*
key_info
=
tbl
->
key_info
+
keyno
;
KEY_PART_INFO
*
key_part
=
key_info
->
key_part
;
KEY_PART_INFO
*
key_part_end
=
key_part
+
key_info
->
key_parts
;
for
(
;
key_part
<
key_part_end
;
key_part
++
)
{
if
(
field
->
eq
(
key_part
->
field
))
return
!
(
key_part
->
key_part_flag
&
HA_PART_KEY_SEG
);
}
if
((
tbl
->
file
->
ha_table_flags
()
&
HA_PRIMARY_KEY_IN_READ_INDEX
)
&&
tbl
->
s
->
primary_key
!=
MAX_KEY
&&
tbl
->
s
->
primary_key
!=
keyno
)
{
key_info
=
tbl
->
key_info
+
tbl
->
s
->
primary_key
;
key_part
=
key_info
->
key_part
;
key_part_end
=
key_part
+
key_info
->
key_parts
;
for
(
;
key_part
<
key_part_end
;
key_part
++
)
{
/*
It does not make sense to use the fact that the engine can read in
a full field if the key if the index is built only over a part
of this field.
*/
if
(
field
->
eq
(
key_part
->
field
))
return
!
(
key_part
->
key_part_flag
&
HA_PART_KEY_SEG
);
}
}
return
FALSE
;
}
}
case
Item
:
:
REF_ITEM
:
case
Item
:
:
REF_ITEM
:
return
uses_index_fields_only
(
item
->
real_item
(),
tbl
,
keyno
,
return
uses_index_fields_only
(
item
->
real_item
(),
tbl
,
keyno
,
...
@@ -288,30 +317,12 @@ void push_index_cond(JOIN_TAB *tab, uint keyno)
...
@@ -288,30 +317,12 @@ void push_index_cond(JOIN_TAB *tab, uint keyno)
{
{
DBUG_ENTER
(
"push_index_cond"
);
DBUG_ENTER
(
"push_index_cond"
);
Item
*
idx_cond
;
Item
*
idx_cond
;
bool
do_index_cond_pushdown
=
((
tab
->
table
->
file
->
index_flags
(
keyno
,
0
,
1
)
&
HA_DO_INDEX_COND_PUSHDOWN
)
&&
optimizer_flag
(
tab
->
join
->
thd
,
OPTIMIZER_SWITCH_INDEX_COND_PUSHDOWN
));
/*
if
((
tab
->
table
->
file
->
index_flags
(
keyno
,
0
,
1
)
&
Do not try index condition pushdown on indexes which have partially-covered
HA_DO_INDEX_COND_PUSHDOWN
)
&&
columns. Unpacking from a column prefix into index tuple is not a supported
optimizer_flag
(
tab
->
join
->
thd
,
OPTIMIZER_SWITCH_INDEX_COND_PUSHDOWN
)
&&
operation in some engines, see e.g. MySQL BUG#42991.
tab
->
join
->
thd
->
lex
->
sql_command
!=
SQLCOM_UPDATE_MULTI
&&
TODO: a better solution would be not to consider partially-covered columns
tab
->
join
->
thd
->
lex
->
sql_command
!=
SQLCOM_DELETE_MULTI
)
as parts of the index and still produce/check index condition for
fully-covered index columns.
*/
KEY
*
key_info
=
tab
->
table
->
key_info
+
keyno
;
for
(
uint
kp
=
0
;
kp
<
key_info
->
key_parts
;
kp
++
)
{
if
((
key_info
->
key_part
[
kp
].
key_part_flag
&
HA_PART_KEY_SEG
))
{
do_index_cond_pushdown
=
FALSE
;
break
;
}
}
if
(
do_index_cond_pushdown
)
{
{
DBUG_EXECUTE
(
"where"
,
DBUG_EXECUTE
(
"where"
,
print_where
(
tab
->
select_cond
,
"full cond"
,
QT_ORDINARY
););
print_where
(
tab
->
select_cond
,
"full cond"
,
QT_ORDINARY
););
...
...
storage/xtradb/dict/dict0dict.c
View file @
deb3b9a1
...
@@ -472,10 +472,12 @@ Looks for column n in an index.
...
@@ -472,10 +472,12 @@ Looks for column n in an index.
ULINT_UNDEFINED if not contained */
ULINT_UNDEFINED if not contained */
UNIV_INTERN
UNIV_INTERN
ulint
ulint
dict_index_get_nth_col_pos
(
dict_index_get_nth_col_
or_prefix_
pos
(
/*=======================*/
/*=======================
==========
*/
const
dict_index_t
*
index
,
/*!< in: index */
const
dict_index_t
*
index
,
/*!< in: index */
ulint
n
)
/*!< in: column number */
ulint
n
,
/*!< in: column number */
ibool
inc_prefix
)
/*!< in: TRUE=consider
column prefixes too */
{
{
const
dict_field_t
*
field
;
const
dict_field_t
*
field
;
const
dict_col_t
*
col
;
const
dict_col_t
*
col
;
...
@@ -497,7 +499,8 @@ dict_index_get_nth_col_pos(
...
@@ -497,7 +499,8 @@ dict_index_get_nth_col_pos(
for
(
pos
=
0
;
pos
<
n_fields
;
pos
++
)
{
for
(
pos
=
0
;
pos
<
n_fields
;
pos
++
)
{
field
=
dict_index_get_nth_field
(
index
,
pos
);
field
=
dict_index_get_nth_field
(
index
,
pos
);
if
(
col
==
field
->
col
&&
field
->
prefix_len
==
0
)
{
if
(
col
==
field
->
col
&&
(
inc_prefix
||
field
->
prefix_len
==
0
))
{
return
(
pos
);
return
(
pos
);
}
}
...
...
storage/xtradb/handler/ha_innodb.cc
View file @
deb3b9a1
...
@@ -125,11 +125,6 @@ static pthread_cond_t commit_cond;
...
@@ -125,11 +125,6 @@ static pthread_cond_t commit_cond;
static
pthread_mutex_t
commit_cond_m
;
static
pthread_mutex_t
commit_cond_m
;
static
bool
innodb_inited
=
0
;
static
bool
innodb_inited
=
0
;
C_MODE_START
static
xtradb_icp_result_t
index_cond_func_innodb
(
void
*
arg
);
C_MODE_END
#define INSIDE_HA_INNOBASE_CC
#define INSIDE_HA_INNOBASE_CC
...
@@ -1958,14 +1953,21 @@ trx_is_strict(
...
@@ -1958,14 +1953,21 @@ trx_is_strict(
/**************************************************************//**
/**************************************************************//**
Resets some fields of a prebuilt struct. The template is used in fast
Resets some fields of a prebuilt struct. The template is used in fast
retrieval of just those column values MySQL needs in its processing. */
retrieval of just those column values MySQL needs in its processing. */
static
void
void
reset_template
(
inline
/*===========*/
ha_innobase
::
reset_template
(
void
)
row_prebuilt_t
*
prebuilt
)
/*!< in/out: prebuilt struct
*/
/*=============================
*/
{
{
ut_ad
(
prebuilt
->
magic_n
==
ROW_PREBUILT_ALLOCATED
);
ut_ad
(
prebuilt
->
magic_n2
==
prebuilt
->
magic_n
);
prebuilt
->
keep_other_fields_on_keyread
=
0
;
prebuilt
->
keep_other_fields_on_keyread
=
0
;
prebuilt
->
read_just_key
=
0
;
prebuilt
->
read_just_key
=
0
;
/* Reset index condition pushdown state */
prebuilt
->
idx_cond
=
NULL
;
prebuilt
->
idx_cond_n_cols
=
0
;
pushed_idx_cond
=
NULL
;
pushed_idx_cond_keyno
=
MAX_KEY
;
}
}
/*****************************************************************//**
/*****************************************************************//**
...
@@ -2027,7 +2029,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
...
@@ -2027,7 +2029,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
we???? */
we???? */
prebuilt
->
used_in_HANDLER
=
TRUE
;
prebuilt
->
used_in_HANDLER
=
TRUE
;
reset_template
(
prebuilt
);
reset_template
();
}
}
/*********************************************************************//**
/*********************************************************************//**
...
@@ -3267,7 +3269,8 @@ ha_innobase::index_flags(
...
@@ -3267,7 +3269,8 @@ ha_innobase::index_flags(
const
const
{
{
return
(
HA_READ_NEXT
|
HA_READ_PREV
|
HA_READ_ORDER
return
(
HA_READ_NEXT
|
HA_READ_PREV
|
HA_READ_ORDER
|
HA_READ_RANGE
|
HA_KEYREAD_ONLY
|
HA_DO_INDEX_COND_PUSHDOWN
);
|
HA_READ_RANGE
|
HA_KEYREAD_ONLY
|
HA_DO_INDEX_COND_PUSHDOWN
);
}
}
/****************************************************************//**
/****************************************************************//**
...
@@ -4093,8 +4096,8 @@ static inline
...
@@ -4093,8 +4096,8 @@ static inline
uint
uint
get_field_offset
(
get_field_offset
(
/*=============*/
/*=============*/
TABLE
*
table
,
/*!< in: MySQL table object */
const
TABLE
*
table
,
/*!< in: MySQL table object */
Field
*
field
)
/*!< in: MySQL field object */
const
Field
*
field
)
/*!< in: MySQL field object */
{
{
return
((
uint
)
(
field
->
ptr
-
table
->
record
[
0
]));
return
((
uint
)
(
field
->
ptr
-
table
->
record
[
0
]));
}
}
...
@@ -4647,45 +4650,170 @@ ha_innobase::store_key_val_for_row(
...
@@ -4647,45 +4650,170 @@ ha_innobase::store_key_val_for_row(
DBUG_RETURN
((
uint
)(
buff
-
buff_start
));
DBUG_RETURN
((
uint
)(
buff
-
buff_start
));
}
}
/**************************************************************//**
Determines if a field is needed in a prebuilt struct 'template'.
@return field to use, or NULL if the field is not needed */
static
const
Field
*
build_template_needs_field
(
/*=======================*/
ibool
index_contains
,
/*!< in:
dict_index_contains_col_or_prefix(
index, i) */
ibool
read_just_key
,
/*!< in: TRUE when MySQL calls
ha_innobase::extra with the
argument HA_EXTRA_KEYREAD; it is enough
to read just columns defined in
the index (i.e., no read of the
clustered index record necessary) */
ibool
fetch_all_in_key
,
/*!< in: true=fetch all fields in
the index */
ibool
fetch_primary_key_cols
,
/*!< in: true=fetch the
primary key columns */
dict_index_t
*
index
,
/*!< in: InnoDB index to use */
const
TABLE
*
table
,
/*!< in: MySQL table object */
ulint
i
)
/*!< in: field index in InnoDB table */
{
const
Field
*
field
=
table
->
field
[
i
];
ut_ad
(
index_contains
==
dict_index_contains_col_or_prefix
(
index
,
i
));
if
(
!
index_contains
)
{
if
(
read_just_key
)
{
/* If this is a 'key read', we do not need
columns that are not in the key */
return
(
NULL
);
}
}
else
if
(
fetch_all_in_key
)
{
/* This field is needed in the query */
return
(
field
);
}
if
(
bitmap_is_set
(
table
->
read_set
,
i
)
||
bitmap_is_set
(
table
->
write_set
,
i
))
{
/* This field is needed in the query */
return
(
field
);
}
if
(
fetch_primary_key_cols
&&
dict_table_col_in_clustered_key
(
index
->
table
,
i
))
{
/* This field is needed in the query */
return
(
field
);
}
/* This field is not needed in the query, skip it */
return
(
NULL
);
}
/**************************************************************//**
Adds a field is to a prebuilt struct 'template'.
@return the field template */
static
mysql_row_templ_t
*
build_template_field
(
/*=================*/
row_prebuilt_t
*
prebuilt
,
/*!< in/out: template */
dict_index_t
*
clust_index
,
/*!< in: InnoDB clustered index */
dict_index_t
*
index
,
/*!< in: InnoDB index to use */
TABLE
*
table
,
/*!< in: MySQL table object */
const
Field
*
field
,
/*!< in: field in MySQL table */
ulint
i
)
/*!< in: field index in InnoDB table */
{
mysql_row_templ_t
*
templ
;
const
dict_col_t
*
col
;
ut_ad
(
field
==
table
->
field
[
i
]);
ut_ad
(
clust_index
->
table
==
index
->
table
);
col
=
dict_table_get_nth_col
(
index
->
table
,
i
);
templ
=
prebuilt
->
mysql_template
+
prebuilt
->
n_template
++
;
UNIV_MEM_INVALID
(
templ
,
sizeof
*
templ
);
templ
->
col_no
=
i
;
templ
->
clust_rec_field_no
=
dict_col_get_clust_pos
(
col
,
clust_index
);
ut_a
(
templ
->
clust_rec_field_no
!=
ULINT_UNDEFINED
);
if
(
dict_index_is_clust
(
index
))
{
templ
->
rec_field_no
=
templ
->
clust_rec_field_no
;
}
else
{
templ
->
rec_field_no
=
dict_index_get_nth_col_pos
(
index
,
i
);
}
if
(
field
->
null_ptr
)
{
templ
->
mysql_null_byte_offset
=
(
ulint
)
((
char
*
)
field
->
null_ptr
-
(
char
*
)
table
->
record
[
0
]);
templ
->
mysql_null_bit_mask
=
(
ulint
)
field
->
null_bit
;
}
else
{
templ
->
mysql_null_bit_mask
=
0
;
}
templ
->
mysql_col_offset
=
(
ulint
)
get_field_offset
(
table
,
field
);
templ
->
mysql_col_len
=
(
ulint
)
field
->
pack_length
();
templ
->
type
=
col
->
mtype
;
templ
->
mysql_type
=
(
ulint
)
field
->
type
();
if
(
templ
->
mysql_type
==
DATA_MYSQL_TRUE_VARCHAR
)
{
templ
->
mysql_length_bytes
=
(
ulint
)
(((
Field_varstring
*
)
field
)
->
length_bytes
);
}
templ
->
charset
=
dtype_get_charset_coll
(
col
->
prtype
);
templ
->
mbminlen
=
col
->
mbminlen
;
templ
->
mbmaxlen
=
col
->
mbmaxlen
;
templ
->
is_unsigned
=
col
->
prtype
&
DATA_UNSIGNED
;
if
(
!
dict_index_is_clust
(
index
)
&&
templ
->
rec_field_no
==
ULINT_UNDEFINED
)
{
prebuilt
->
need_to_access_clustered
=
TRUE
;
}
if
(
prebuilt
->
mysql_prefix_len
<
templ
->
mysql_col_offset
+
templ
->
mysql_col_len
)
{
prebuilt
->
mysql_prefix_len
=
templ
->
mysql_col_offset
+
templ
->
mysql_col_len
;
}
if
(
templ
->
type
==
DATA_BLOB
)
{
prebuilt
->
templ_contains_blob
=
TRUE
;
}
return
(
templ
);
}
/**************************************************************//**
/**************************************************************//**
Builds a 'template' to the prebuilt struct. The template is used in fast
Builds a 'template' to the prebuilt struct. The template is used in fast
retrieval of just those column values MySQL needs in its processing. */
retrieval of just those column values MySQL needs in its processing. */
static
UNIV_INTERN
void
void
build_template
(
ha_innobase
::
build_template
(
/*===========*/
/*========================*/
row_prebuilt_t
*
prebuilt
,
/*!< in/out: prebuilt struct */
bool
whole_row
)
/*!< in: true=ROW_MYSQL_WHOLE_ROW,
THD
*
thd
,
/*!< in: current user thread, used
false=ROW_MYSQL_REC_FIELDS */
only if templ_type is
ROW_MYSQL_REC_FIELDS */
TABLE
*
table
,
/* in: MySQL table */
ha_innobase
*
file
,
/* in: ha_innobase handler */
uint
templ_type
)
/* in: ROW_MYSQL_WHOLE_ROW or
ROW_MYSQL_REC_FIELDS */
{
{
dict_index_t
*
index
;
dict_index_t
*
index
;
dict_index_t
*
clust_index
;
dict_index_t
*
clust_index
;
mysql_row_templ_t
*
templ
;
ulint
n_fields
;
Field
*
field
;
ulint
n_fields
,
n_stored_fields
;
ulint
n_requested_fields
=
0
;
ibool
fetch_all_in_key
=
FALSE
;
ibool
fetch_all_in_key
=
FALSE
;
ibool
fetch_primary_key_cols
=
FALSE
;
ibool
fetch_primary_key_cols
=
FALSE
;
ulint
sql_idx
,
innodb_idx
=
0
;
ulint
i
;
/* byte offset of the end of last requested column */
ulint
mysql_prefix_len
=
0
;
ibool
do_idx_cond_push
=
FALSE
;
ibool
need_second_pass
=
FALSE
;
if
(
prebuilt
->
select_lock_type
==
LOCK_X
)
{
if
(
prebuilt
->
select_lock_type
==
LOCK_X
)
{
/* We always retrieve the whole clustered index record if we
/* We always retrieve the whole clustered index record if we
use exclusive row level locks, for example, if the read is
use exclusive row level locks, for example, if the read is
done in an UPDATE statement. */
done in an UPDATE statement. */
templ_type
=
ROW_MYSQL_WHOLE_ROW
;
whole_row
=
true
;
}
}
else
if
(
!
whole_row
)
{
if
(
templ_type
==
ROW_MYSQL_REC_FIELDS
)
{
if
(
prebuilt
->
hint_need_to_fetch_extra_cols
if
(
prebuilt
->
hint_need_to_fetch_extra_cols
==
ROW_RETRIEVE_ALL_COLS
)
{
==
ROW_RETRIEVE_ALL_COLS
)
{
...
@@ -4702,7 +4830,7 @@ build_template(
...
@@ -4702,7 +4830,7 @@ build_template(
fetch_all_in_key
=
TRUE
;
fetch_all_in_key
=
TRUE
;
}
else
{
}
else
{
templ_type
=
ROW_MYSQL_WHOLE_ROW
;
whole_row
=
true
;
}
}
}
else
if
(
prebuilt
->
hint_need_to_fetch_extra_cols
}
else
if
(
prebuilt
->
hint_need_to_fetch_extra_cols
==
ROW_RETRIEVE_PRIMARY_KEY
)
{
==
ROW_RETRIEVE_PRIMARY_KEY
)
{
...
@@ -4719,182 +4847,206 @@ build_template(
...
@@ -4719,182 +4847,206 @@ build_template(
clust_index
=
dict_table_get_first_index
(
prebuilt
->
table
);
clust_index
=
dict_table_get_first_index
(
prebuilt
->
table
);
if
(
templ_type
==
ROW_MYSQL_REC_FIELDS
)
{
index
=
whole_row
?
clust_index
:
prebuilt
->
index
;
index
=
prebuilt
->
index
;
}
else
{
prebuilt
->
need_to_access_clustered
=
(
index
==
clust_index
);
index
=
clust_index
;
}
if
(
index
==
clust_index
)
{
prebuilt
->
need_to_access_clustered
=
TRUE
;
}
else
{
prebuilt
->
need_to_access_clustered
=
FALSE
;
/* Below we check column by column if we need to access
/* Below we check column by column if we need to access
the clustered index */
the clustered index. */
}
n_fields
=
(
ulint
)
table
->
s
->
fields
;
/* number of columns */
n_fields
=
(
ulint
)
table
->
s
->
fields
;
/* number of columns */
n_stored_fields
=
(
ulint
)
table
->
s
->
stored_fields
;
/* number of stored columns */
if
(
!
prebuilt
->
mysql_template
)
{
if
(
!
prebuilt
->
mysql_template
)
{
prebuilt
->
mysql_template
=
(
mysql_row_templ_t
*
)
prebuilt
->
mysql_template
=
(
mysql_row_templ_t
*
)
mem_alloc
(
n_
stored_
fields
*
sizeof
(
mysql_row_templ_t
));
mem_alloc
(
n_fields
*
sizeof
(
mysql_row_templ_t
));
}
}
prebuilt
->
template_type
=
templ_type
;
prebuilt
->
template_type
=
whole_row
?
ROW_MYSQL_WHOLE_ROW
:
ROW_MYSQL_REC_FIELDS
;
prebuilt
->
null_bitmap_len
=
table
->
s
->
null_bytes
;
prebuilt
->
null_bitmap_len
=
table
->
s
->
null_bytes
;
/* Prepare to build prebuilt->mysql_template[]. */
prebuilt
->
templ_contains_blob
=
FALSE
;
prebuilt
->
templ_contains_blob
=
FALSE
;
prebuilt
->
mysql_prefix_len
=
0
;
prebuilt
->
n_template
=
0
;
prebuilt
->
idx_cond_n_cols
=
0
;
/* Note that in InnoDB, i is the column number in the table.
MySQL calls columns 'fields'. */
/*
if
(
active_index
!=
MAX_KEY
&&
active_index
==
pushed_idx_cond_keyno
)
{
Setup index condition pushdown (note: we don't need to check if
/* Push down an index condition or an end_range check. */
this is a scan on primary key as that is checked in idx_cond_push)
for
(
i
=
0
;
i
<
n_fields
;
i
++
)
{
*/
const
ibool
index_contains
if
(
file
->
active_index
==
file
->
pushed_idx_cond_keyno
&&
=
dict_index_contains_col_or_prefix
(
index
,
i
);
file
->
active_index
!=
MAX_KEY
&&
templ_type
==
ROW_MYSQL_REC_FIELDS
)
/* Test if an end_range or an index condition
do_idx_cond_push
=
need_second_pass
=
TRUE
;
refers to the field. Note that "index" and
"index_contains" may refer to the clustered index.
/* Note that in InnoDB, i is the column number. MySQL calls columns
Index condition pushdown is relative to prebuilt->index
'fields'. */
(the index that is being looked up first). */
for
(
sql_idx
=
0
;
sql_idx
<
n_fields
;
sql_idx
++
)
{
templ
=
prebuilt
->
mysql_template
+
n_requested_fields
;
/* When join_read_always_key() invokes this
field
=
table
->
field
[
sql_idx
];
code via handler::ha_index_init() and
if
(
!
field
->
stored_in_db
)
ha_innobase::index_init(), end_range is not
goto
skip_field
;
yet initialized. Because of that, we must
always check for index_contains, instead of
if
(
UNIV_LIKELY
(
templ_type
==
ROW_MYSQL_REC_FIELDS
))
{
the subset
/* Decide which columns we should fetch
field->part_of_key.is_set(active_index)
and which we can skip. */
which would be acceptable if end_range==NULL. */
register
const
ibool
index_contains_field
=
if
(
index
==
prebuilt
->
index
dict_index_contains_col_or_prefix
(
index
,
innodb_idx
);
?
index_contains
register
const
ibool
index_covers_field
=
:
dict_index_contains_col_or_prefix
(
field
->
part_of_key
.
is_set
(
file
->
active_index
);
prebuilt
->
index
,
i
))
{
/* Needed in ICP */
if
(
!
index_contains_field
&&
prebuilt
->
read_just_key
)
{
const
Field
*
field
;
/* If this is a 'key read', we do not need
mysql_row_templ_t
*
templ
;
columns that are not in the key */
goto
skip_field
;
if
(
whole_row
)
{
field
=
table
->
field
[
i
];
}
else
{
field
=
build_template_needs_field
(
index_contains
,
prebuilt
->
read_just_key
,
fetch_all_in_key
,
fetch_primary_key_cols
,
index
,
table
,
i
);
if
(
!
field
)
{
continue
;
}
}
if
(
index_contains_field
&&
fetch_all_in_key
)
{
/* This field is needed in the query */
goto
include_field
;
}
}
if
(
bitmap_is_set
(
table
->
read_set
,
sql_idx
)
||
templ
=
build_template_field
(
bitmap_is_set
(
table
->
write_set
,
sql_idx
))
{
prebuilt
,
clust_index
,
index
,
/* This field is needed in the query */
table
,
field
,
i
);
prebuilt
->
idx_cond_n_cols
++
;
ut_ad
(
prebuilt
->
idx_cond_n_cols
==
prebuilt
->
n_template
);
goto
include_field
;
if
(
index
==
prebuilt
->
index
)
{
templ
->
icp_rec_field_no
=
templ
->
rec_field_no
;
}
else
{
templ
->
icp_rec_field_no
=
dict_index_get_nth_col_pos
(
prebuilt
->
index
,
i
);
}
if
(
dict_index_is_clust
(
prebuilt
->
index
))
{
ut_ad
(
templ
->
icp_rec_field_no
!=
ULINT_UNDEFINED
);
/* If the primary key includes
a column prefix, use it in
index condition pushdown,
because the condition is
evaluated before fetching any
off-page (externally stored)
columns. */
if
(
templ
->
icp_rec_field_no
<
prebuilt
->
index
->
n_uniq
)
{
/* This is a key column;
all set. */
continue
;
}
}
}
else
if
(
templ
->
icp_rec_field_no
if
(
fetch_primary_key_cols
!=
ULINT_UNDEFINED
)
{
&&
dict_table_col_in_clustered_key
(
continue
;
index
->
table
,
innodb_idx
))
{
/* This field is needed in the query */
goto
include_field
;
}
}
/* This field is not needed in the query, skip it */
/* This is a column prefix index.
The column prefix can be used in
goto
skip_field
;
an end_range comparison. */
include_field:
if
(
do_idx_cond_push
&&
templ
->
icp_rec_field_no
((
need_second_pass
&&
!
index_covers_field
)
||
=
dict_index_get_nth_col_or_prefix_pos
(
(
!
need_second_pass
&&
index_covers_field
)))
prebuilt
->
index
,
i
,
TRUE
);
goto
skip_field
;
ut_ad
(
templ
->
icp_rec_field_no
!=
ULINT_UNDEFINED
);
/* Index condition pushdown can be used on
all columns of a secondary index, and on
the PRIMARY KEY columns. */
/* TODO: enable this assertion
(but first ensure that end_range is
valid here and use an accurate condition
for end_range)
ut_ad(!dict_index_is_clust(prebuilt->index)
|| templ->rec_field_no
< prebuilt->index->n_uniq);
*/
}
}
}
n_requested_fields
++
;
templ
->
col_no
=
innodb_idx
;
ut_ad
(
prebuilt
->
idx_cond_n_cols
>
0
);
templ
->
clust_rec_field_no
=
dict_col_get_clust_pos
(
ut_ad
(
prebuilt
->
idx_cond_n_cols
==
prebuilt
->
n_template
);
&
index
->
table
->
cols
[
innodb_idx
],
clust_index
);
ut_ad
(
templ
->
clust_rec_field_no
!=
ULINT_UNDEFINED
);
if
(
index
==
clust_index
)
{
/* Include the fields that are not needed in index condition
templ
->
rec_field_no
=
templ
->
clust_rec_field_no
;
pushdown. */
for
(
i
=
0
;
i
<
n_fields
;
i
++
)
{
const
ibool
index_contains
=
dict_index_contains_col_or_prefix
(
index
,
i
);
if
(
index
==
prebuilt
->
index
?
!
index_contains
:
!
dict_index_contains_col_or_prefix
(
prebuilt
->
index
,
i
))
{
/* Not needed in ICP */
const
Field
*
field
;
if
(
whole_row
)
{
field
=
table
->
field
[
i
];
}
else
{
}
else
{
templ
->
rec_field_no
=
dict_index_get_nth_col_pos
(
field
=
build_template_needs_field
(
index
,
innodb_idx
);
index_contains
,
if
(
templ
->
rec_field_no
==
ULINT_UNDEFINED
)
{
prebuilt
->
read_just_key
,
prebuilt
->
need_to_access_clustered
=
TRUE
;
fetch_all_in_key
,
fetch_primary_key_cols
,
index
,
table
,
i
);
if
(
!
field
)
{
continue
;
}
}
}
}
if
(
field
->
null_ptr
)
{
build_template_field
(
prebuilt
,
templ
->
mysql_null_byte_offset
=
clust_index
,
index
,
(
ulint
)
((
char
*
)
field
->
null_ptr
table
,
field
,
i
);
-
(
char
*
)
table
->
record
[
0
]);
templ
->
mysql_null_bit_mask
=
(
ulint
)
field
->
null_bit
;
}
else
{
templ
->
mysql_null_bit_mask
=
0
;
}
}
templ
->
mysql_col_offset
=
(
ulint
)
get_field_offset
(
table
,
field
);
templ
->
mysql_col_len
=
(
ulint
)
field
->
pack_length
();
if
(
mysql_prefix_len
<
templ
->
mysql_col_offset
+
templ
->
mysql_col_len
)
{
mysql_prefix_len
=
templ
->
mysql_col_offset
+
templ
->
mysql_col_len
;
}
}
templ
->
type
=
index
->
table
->
cols
[
innodb_idx
].
mtype
;
templ
->
mysql_type
=
(
ulint
)
field
->
type
();
if
(
templ
->
mysql_type
==
DATA_MYSQL_TRUE_VARCHAR
)
{
prebuilt
->
idx_cond
=
this
;
templ
->
mysql_length_bytes
=
(
ulint
)
}
else
{
(((
Field_varstring
*
)
field
)
->
length_bytes
);
/* No index condition pushdown */
}
prebuilt
->
idx_cond
=
NULL
;
templ
->
charset
=
dtype_get_charset_coll
(
for
(
i
=
0
;
i
<
n_fields
;
i
++
)
{
index
->
table
->
cols
[
innodb_idx
].
prtype
);
const
Field
*
field
;
templ
->
mbminlen
=
index
->
table
->
cols
[
innodb_idx
].
mbminlen
;
templ
->
mbmaxlen
=
index
->
table
->
cols
[
innodb_idx
].
mbmaxlen
;
if
(
whole_row
)
{
templ
->
is_unsigned
=
index
->
table
->
cols
[
innodb_idx
].
prtype
field
=
table
->
field
[
i
];
&
DATA_UNSIGNED
;
}
else
{
if
(
templ
->
type
==
DATA_BLOB
)
{
field
=
build_template_needs_field
(
prebuilt
->
templ_contains_blob
=
TRUE
;
dict_index_contains_col_or_prefix
(
}
index
,
i
),
skip_field:
prebuilt
->
read_just_key
,
if
(
need_second_pass
&&
(
sql_idx
+
1
==
n_fields
))
fetch_all_in_key
,
{
fetch_primary_key_cols
,
prebuilt
->
n_index_fields
=
n_requested_fields
;
index
,
table
,
i
);
need_second_pass
=
FALSE
;
if
(
!
field
)
{
sql_idx
=
(
~
(
ulint
)
0
);
/* to start from 0 */
continue
;
innodb_idx
=
(
~
(
ulint
)
0
);
/* to start from 0 */
///psergey-merge-merge-last-change
}
if
(
field
->
stored_in_db
)
{
innodb_idx
++
;
}
}
}
}
prebuilt
->
n_template
=
n_requested_fields
;
build_template_field
(
prebuilt
,
clust_index
,
index
,
prebuilt
->
mysql_prefix_len
=
mysql_prefix_len
;
table
,
field
,
i
);
if
(
do_idx_cond_push
)
{
prebuilt
->
idx_cond_func
=
index_cond_func_innodb
;
prebuilt
->
idx_cond_func_arg
=
file
;
}
}
else
{
prebuilt
->
idx_cond_func
=
NULL
;
prebuilt
->
n_index_fields
=
n_requested_fields
;
}
}
if
(
index
!=
clust_index
&&
prebuilt
->
need_to_access_clustered
)
{
if
(
index
!=
clust_index
&&
prebuilt
->
need_to_access_clustered
)
{
/* Change rec_field_no's to correspond to the clustered index
/* Change rec_field_no's to correspond to the clustered index
record */
record */
for
(
ulint
i
=
do_idx_cond_push
?
prebuilt
->
n_index_fields
:
0
;
for
(
i
=
0
;
i
<
prebuilt
->
n_template
;
i
++
)
{
i
<
n_requested_fields
;
i
++
)
{
mysql_row_templ_t
*
templ
templ
=
prebuilt
->
mysql_template
+
i
;
=
&
prebuilt
->
mysql_template
[
i
]
;
templ
->
rec_field_no
=
templ
->
clust_rec_field_no
;
templ
->
rec_field_no
=
templ
->
clust_rec_field_no
;
}
}
}
}
...
@@ -5157,7 +5309,7 @@ ha_innobase::write_row(
...
@@ -5157,7 +5309,7 @@ ha_innobase::write_row(
/* Build the template used in converting quickly between
/* Build the template used in converting quickly between
the two database formats */
the two database formats */
build_template
(
prebuilt
,
NULL
,
table
,
this
,
ROW_MYSQL_WHOLE_ROW
);
build_template
(
true
);
}
}
innodb_srv_conc_enter_innodb
(
prebuilt
->
trx
);
innodb_srv_conc_enter_innodb
(
prebuilt
->
trx
);
...
@@ -5858,8 +6010,7 @@ ha_innobase::index_read(
...
@@ -5858,8 +6010,7 @@ ha_innobase::index_read(
necessarily prebuilt->index, but can also be the clustered index */
necessarily prebuilt->index, but can also be the clustered index */
if
(
prebuilt
->
sql_stat_start
)
{
if
(
prebuilt
->
sql_stat_start
)
{
build_template
(
prebuilt
,
user_thd
,
table
,
this
,
build_template
(
false
);
ROW_MYSQL_REC_FIELDS
);
}
}
if
(
key_ptr
)
{
if
(
key_ptr
)
{
...
@@ -6069,7 +6220,7 @@ ha_innobase::change_active_index(
...
@@ -6069,7 +6220,7 @@ ha_innobase::change_active_index(
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
build_template
(
prebuilt
,
user_thd
,
table
,
this
,
ROW_MYSQL_REC_FIELDS
);
build_template
(
false
);
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
}
}
...
@@ -8406,7 +8557,7 @@ ha_innobase::check(
...
@@ -8406,7 +8557,7 @@ ha_innobase::check(
/* Build the template; we will use a dummy template
/* Build the template; we will use a dummy template
in index scans done in checking */
in index scans done in checking */
build_template
(
prebuilt
,
NULL
,
table
,
this
,
ROW_MYSQL_WHOLE_ROW
);
build_template
(
true
);
}
}
if
(
prebuilt
->
table
->
ibd_file_missing
)
{
if
(
prebuilt
->
table
->
ibd_file_missing
)
{
...
@@ -8898,12 +9049,7 @@ ha_innobase::extra(
...
@@ -8898,12 +9049,7 @@ ha_innobase::extra(
}
}
break
;
break
;
case
HA_EXTRA_RESET_STATE
:
case
HA_EXTRA_RESET_STATE
:
reset_template
(
prebuilt
);
reset_template
();
/* Reset index condition pushdown state */
pushed_idx_cond
=
FALSE
;
pushed_idx_cond_keyno
=
MAX_KEY
;
prebuilt
->
idx_cond_func
=
NULL
;
in_range_check_pushed_down
=
FALSE
;
break
;
break
;
case
HA_EXTRA_NO_KEYREAD
:
case
HA_EXTRA_NO_KEYREAD
:
prebuilt
->
read_just_key
=
0
;
prebuilt
->
read_just_key
=
0
;
...
@@ -8949,14 +9095,8 @@ ha_innobase::reset()
...
@@ -8949,14 +9095,8 @@ ha_innobase::reset()
row_mysql_prebuilt_free_blob_heap
(
prebuilt
);
row_mysql_prebuilt_free_blob_heap
(
prebuilt
);
}
}
reset_template
(
prebuilt
);
reset_template
();
/* Reset index condition pushdown state */
pushed_idx_cond_keyno
=
MAX_KEY
;
pushed_idx_cond
=
NULL
;
in_range_check_pushed_down
=
FALSE
;
ds_mrr
.
dsmrr_close
();
ds_mrr
.
dsmrr_close
();
prebuilt
->
idx_cond_func
=
NULL
;
/* TODO: This should really be reset in reset_template() but for now
/* TODO: This should really be reset in reset_template() but for now
it's safer to do it explicitly here. */
it's safer to do it explicitly here. */
...
@@ -9006,7 +9146,7 @@ ha_innobase::start_stmt(
...
@@ -9006,7 +9146,7 @@ ha_innobase::start_stmt(
prebuilt
->
sql_stat_start
=
TRUE
;
prebuilt
->
sql_stat_start
=
TRUE
;
prebuilt
->
hint_need_to_fetch_extra_cols
=
0
;
prebuilt
->
hint_need_to_fetch_extra_cols
=
0
;
reset_template
(
prebuilt
);
reset_template
();
if
(
!
prebuilt
->
mysql_has_locked
)
{
if
(
!
prebuilt
->
mysql_has_locked
)
{
/* This handle is for a temporary table created inside
/* This handle is for a temporary table created inside
...
@@ -9125,7 +9265,7 @@ ha_innobase::external_lock(
...
@@ -9125,7 +9265,7 @@ ha_innobase::external_lock(
prebuilt
->
sql_stat_start
=
TRUE
;
prebuilt
->
sql_stat_start
=
TRUE
;
prebuilt
->
hint_need_to_fetch_extra_cols
=
0
;
prebuilt
->
hint_need_to_fetch_extra_cols
=
0
;
reset_template
(
prebuilt
);
reset_template
();
if
(
lock_type
==
F_WRLCK
)
{
if
(
lock_type
==
F_WRLCK
)
{
...
@@ -9308,7 +9448,7 @@ ha_innobase::transactional_table_lock(
...
@@ -9308,7 +9448,7 @@ ha_innobase::transactional_table_lock(
prebuilt
->
sql_stat_start
=
TRUE
;
prebuilt
->
sql_stat_start
=
TRUE
;
prebuilt
->
hint_need_to_fetch_extra_cols
=
0
;
prebuilt
->
hint_need_to_fetch_extra_cols
=
0
;
reset_template
(
prebuilt
);
reset_template
();
if
(
lock_type
==
F_WRLCK
)
{
if
(
lock_type
==
F_WRLCK
)
{
prebuilt
->
select_lock_type
=
LOCK_X
;
prebuilt
->
select_lock_type
=
LOCK_X
;
...
@@ -12153,39 +12293,47 @@ bool ha_innobase::is_thd_killed()
...
@@ -12153,39 +12293,47 @@ bool ha_innobase::is_thd_killed()
* Index Condition Pushdown interface implementation
* Index Condition Pushdown interface implementation
*/
*/
C_MODE_START
/*************************************************************//**
InnoDB index push-down condition check
/*
@return ICP_NO_MATCH, ICP_MATCH, or ICP_OUT_OF_RANGE */
Index condition check function to be called from within Innobase.
extern
"C"
UNIV_INTERN
See note on ICP_RESULT for return values description.
enum
icp_result
*/
innobase_index_cond
(
/*================*/
static
xtradb_icp_result_t
index_cond_func_innodb
(
void
*
arg
)
void
*
file
)
/*!< in/out: pointer to ha_innobase */
{
{
ha_innobase
*
h
=
(
ha_innobase
*
)
arg
;
ha_innobase
*
h
=
(
ha_innobase
*
)
file
;
if
(
h
->
is_thd_killed
())
if
(
h
->
is_thd_killed
())
return
XTRADB_
ICP_ABORTED_BY_USER
;
return
ICP_ABORTED_BY_USER
;
if
(
h
->
end_range
)
if
(
h
->
end_range
)
{
{
if
(
h
->
compare_key2
(
h
->
end_range
)
>
0
)
if
(
h
->
compare_key2
(
h
->
end_range
)
>
0
)
return
XTRADB_
ICP_OUT_OF_RANGE
;
/* caller should return HA_ERR_END_OF_FILE already */
return
ICP_OUT_OF_RANGE
;
/* caller should return HA_ERR_END_OF_FILE already */
}
}
return
h
->
pushed_idx_cond
->
val_int
()
?
XTRADB_ICP_MATCH
:
XTRADB_
ICP_NO_MATCH
;
return
h
->
pushed_idx_cond
->
val_int
()
?
ICP_MATCH
:
ICP_NO_MATCH
;
}
}
C_MODE_END
/** Attempt to push down an index condition.
* @param[in] keyno MySQL key number
* @param[in] idx_cond Index condition to be checked
Item
*
ha_innobase
::
idx_cond_push
(
uint
keyno_arg
,
Item
*
idx_cond_arg
)
* @return idx_cond if pushed; NULL if not pushed
{
*/
if
(
keyno_arg
!=
primary_key
&&
prebuilt
->
select_lock_type
!=
LOCK_X
)
UNIV_INTERN
{
class
Item
*
pushed_idx_cond_keyno
=
keyno_arg
;
ha_innobase
::
idx_cond_push
(
pushed_idx_cond
=
idx_cond_arg
;
uint
keyno
,
in_range_check_pushed_down
=
TRUE
;
class
Item
*
idx_cond
)
return
NULL
;
/* Table handler will check the entire condition */
{
}
DBUG_ENTER
(
"ha_innobase::idx_cond_push"
);
return
idx_cond_arg
;
/* Table handler will not make any checks */
DBUG_ASSERT
(
keyno
!=
MAX_KEY
);
DBUG_ASSERT
(
idx_cond
!=
NULL
);
pushed_idx_cond
=
idx_cond
;
pushed_idx_cond_keyno
=
keyno
;
in_range_check_pushed_down
=
TRUE
;
/* Table handler will check the entire condition */
DBUG_RETURN
(
NULL
);
}
}
storage/xtradb/handler/ha_innodb.h
View file @
deb3b9a1
...
@@ -223,26 +223,79 @@ class ha_innobase: public handler
...
@@ -223,26 +223,79 @@ class ha_innobase: public handler
bool
check_if_incompatible_data
(
HA_CREATE_INFO
*
info
,
bool
check_if_incompatible_data
(
HA_CREATE_INFO
*
info
,
uint
table_changes
);
uint
table_changes
);
bool
check_if_supported_virtual_columns
(
void
)
{
return
TRUE
;
}
bool
check_if_supported_virtual_columns
(
void
)
{
return
TRUE
;
}
private:
/** Builds a 'template' to the prebuilt struct.
The template is used in fast retrieval of just those column
values MySQL needs in its processing.
@param whole_row true if access is needed to a whole row,
false if accessing individual fields is enough */
void
build_template
(
bool
whole_row
);
/** Resets a query execution 'template'.
@see build_template() */
inline
void
reset_template
();
public:
public:
/**
/** @name Multi Range Read interface @{ */
* Multi Range Read interface
/** Initialize multi range read @see DsMrr_impl::dsmrr_init
* @param seq
* @param seq_init_param
* @param n_ranges
* @param mode
* @param buf
*/
int
multi_range_read_init
(
RANGE_SEQ_IF
*
seq
,
void
*
seq_init_param
,
uint
n_ranges
,
uint
mode
,
HANDLER_BUFFER
*
buf
);
/** Process next multi range read @see DsMrr_impl::dsmrr_next
* @param range_info
*/
*/
int
multi_range_read_init
(
RANGE_SEQ_IF
*
seq
,
void
*
seq_init_param
,
uint
n_ranges
,
uint
mode
,
HANDLER_BUFFER
*
buf
);
int
multi_range_read_next
(
range_id_t
*
range_info
);
int
multi_range_read_next
(
range_id_t
*
range_info
);
/** Initialize multi range read and get information.
* @see ha_myisam::multi_range_read_info_const
* @see DsMrr_impl::dsmrr_info_const
* @param keyno
* @param seq
* @param seq_init_param
* @param n_ranges
* @param bufsz
* @param flags
* @param cost
*/
ha_rows
multi_range_read_info_const
(
uint
keyno
,
RANGE_SEQ_IF
*
seq
,
ha_rows
multi_range_read_info_const
(
uint
keyno
,
RANGE_SEQ_IF
*
seq
,
void
*
seq_init_param
,
void
*
seq_init_param
,
uint
n_ranges
,
uint
*
bufsz
,
uint
n_ranges
,
uint
*
bufsz
,
uint
*
flags
,
COST_VECT
*
cost
);
uint
*
flags
,
COST_VECT
*
cost
);
/** Initialize multi range read and get information.
* @see DsMrr_impl::dsmrr_info
* @param keyno
* @param n_ranges
* @param keys
* @param key_parts
* @param bufsz
* @param flags
* @param cost
*/
ha_rows
multi_range_read_info
(
uint
keyno
,
uint
n_ranges
,
uint
keys
,
ha_rows
multi_range_read_info
(
uint
keyno
,
uint
n_ranges
,
uint
keys
,
uint
key_parts
,
uint
*
bufsz
,
uint
key_parts
,
uint
*
bufsz
,
uint
*
flags
,
COST_VECT
*
cost
);
uint
*
flags
,
COST_VECT
*
cost
);
DsMrr_impl
ds_mrr
;
Item
*
idx_cond_push
(
uint
keyno
,
Item
*
idx_cond
);
/** Attempt to push down an index condition.
* @param[in] keyno MySQL key number
* @param[in] idx_cond Index condition to be checked
* @return idx_cond if pushed; NULL if not pushed
*/
class
Item
*
idx_cond_push
(
uint
keyno
,
class
Item
*
idx_cond
);
/* An helper function for index_cond_func_innodb: */
/* An helper function for index_cond_func_innodb: */
bool
is_thd_killed
();
bool
is_thd_killed
();
private:
/** The multi range read session object */
DsMrr_impl
ds_mrr
;
/* @} */
};
};
/* Some accessor functions which the InnoDB plugin needs, but which
/* Some accessor functions which the InnoDB plugin needs, but which
...
...
storage/xtradb/include/dict0dict.h
View file @
deb3b9a1
...
@@ -839,6 +839,18 @@ dict_index_get_nth_col_pos(
...
@@ -839,6 +839,18 @@ dict_index_get_nth_col_pos(
const
dict_index_t
*
index
,
/*!< in: index */
const
dict_index_t
*
index
,
/*!< in: index */
ulint
n
);
/*!< in: column number */
ulint
n
);
/*!< in: column number */
/********************************************************************//**
/********************************************************************//**
Looks for column n in an index.
@return position in internal representation of the index;
ULINT_UNDEFINED if not contained */
UNIV_INTERN
ulint
dict_index_get_nth_col_or_prefix_pos
(
/*=================================*/
const
dict_index_t
*
index
,
/*!< in: index */
ulint
n
,
/*!< in: column number */
ibool
inc_prefix
);
/*!< in: TRUE=consider
column prefixes too */
/********************************************************************//**
Returns TRUE if the index contains a column or a prefix of that column.
Returns TRUE if the index contains a column or a prefix of that column.
@return TRUE if contains the column or its prefix */
@return TRUE if contains the column or its prefix */
UNIV_INTERN
UNIV_INTERN
...
...
storage/xtradb/include/dict0dict.ic
View file @
deb3b9a1
...
@@ -656,6 +656,20 @@ dict_index_get_nth_col_no(
...
@@ -656,6 +656,20 @@ dict_index_get_nth_col_no(
return(dict_col_get_no(dict_index_get_nth_col(index, pos)));
return(dict_col_get_no(dict_index_get_nth_col(index, pos)));
}
}
/********************************************************************//**
Looks for column n in an index.
@return position in internal representation of the index;
ULINT_UNDEFINED if not contained */
UNIV_INLINE
ulint
dict_index_get_nth_col_pos(
/*=======================*/
const dict_index_t* index, /*!< in: index */
ulint n) /*!< in: column number */
{
return(dict_index_get_nth_col_or_prefix_pos(index, n, FALSE));
}
#ifndef UNIV_HOTBACKUP
#ifndef UNIV_HOTBACKUP
/********************************************************************//**
/********************************************************************//**
Returns the minimum data size of an index record.
Returns the minimum data size of an index record.
...
...
storage/xtradb/include/ha_prototypes.h
View file @
deb3b9a1
...
@@ -247,6 +247,15 @@ innobase_get_at_most_n_mbchars(
...
@@ -247,6 +247,15 @@ innobase_get_at_most_n_mbchars(
ulint
data_len
,
/*!< in: length of the string in bytes */
ulint
data_len
,
/*!< in: length of the string in bytes */
const
char
*
str
);
/*!< in: character string */
const
char
*
str
);
/*!< in: character string */
/*************************************************************//**
InnoDB index push-down condition check
@return ICP_NO_MATCH, ICP_MATCH, or ICP_OUT_OF_RANGE */
UNIV_INTERN
enum
icp_result
innobase_index_cond
(
/*================*/
void
*
file
)
/*!< in/out: pointer to ha_innobase */
__attribute__
((
nonnull
,
warn_unused_result
));
/******************************************************************//**
/******************************************************************//**
Returns true if the thread supports XA,
Returns true if the thread supports XA,
global value of innodb_supports_xa if thd is NULL.
global value of innodb_supports_xa if thd is NULL.
...
...
storage/xtradb/include/row0mysql.h
View file @
deb3b9a1
...
@@ -539,6 +539,10 @@ struct mysql_row_templ_struct {
...
@@ -539,6 +539,10 @@ struct mysql_row_templ_struct {
Innobase record in the clustered index;
Innobase record in the clustered index;
not defined if template_type is
not defined if template_type is
ROW_MYSQL_WHOLE_ROW */
ROW_MYSQL_WHOLE_ROW */
ulint
icp_rec_field_no
;
/*!< field number of the column in an
Innobase record in the current index;
not defined unless
index condition pushdown is used */
ulint
mysql_col_offset
;
/*!< offset of the column in the MySQL
ulint
mysql_col_offset
;
/*!< offset of the column in the MySQL
row format */
row format */
ulint
mysql_col_len
;
/*!< length of the column in the MySQL
ulint
mysql_col_len
;
/*!< length of the column in the MySQL
...
@@ -577,16 +581,6 @@ struct mysql_row_templ_struct {
...
@@ -577,16 +581,6 @@ struct mysql_row_templ_struct {
#define ROW_PREBUILT_ALLOCATED 78540783
#define ROW_PREBUILT_ALLOCATED 78540783
#define ROW_PREBUILT_FREED 26423527
#define ROW_PREBUILT_FREED 26423527
typedef
enum
xtradb_icp_result
{
XTRADB_ICP_ERROR
=-
1
,
XTRADB_ICP_NO_MATCH
=
0
,
XTRADB_ICP_MATCH
=
1
,
XTRADB_ICP_OUT_OF_RANGE
=
2
,
XTRADB_ICP_ABORTED_BY_USER
=
3
,
}
xtradb_icp_result_t
;
typedef
xtradb_icp_result_t
(
*
index_cond_func_t
)(
void
*
param
);
/** A struct for (sometimes lazily) prebuilt structures in an Innobase table
/** A struct for (sometimes lazily) prebuilt structures in an Innobase table
handle used within MySQL; these are used to save CPU time. */
handle used within MySQL; these are used to save CPU time. */
...
@@ -784,16 +778,15 @@ struct row_prebuilt_struct {
...
@@ -784,16 +778,15 @@ struct row_prebuilt_struct {
store it here so that we can return
store it here so that we can return
it to MySQL */
it to MySQL */
/*----------------------*/
/*----------------------*/
void
*
idx_cond
;
/*!< In ICP, pointer to a ha_innobase,
passed to innobase_index_cond().
NULL if index condition pushdown is
not used. */
ulint
idx_cond_n_cols
;
/*!< Number of fields in idx_cond_cols.
0 if and only if idx_cond == NULL. */
/*----------------------*/
ulint
magic_n2
;
/*!< this should be the same as
ulint
magic_n2
;
/*!< this should be the same as
magic_n */
magic_n */
/*----------------------*/
index_cond_func_t
idx_cond_func
;
/* Index Condition Pushdown function,
or NULL if there is none set */
void
*
idx_cond_func_arg
;
/* ICP function argument */
ulint
n_index_fields
;
/* Number of fields at the start of
mysql_template. Valid only when using
ICP. */
/*----------------------*/
};
};
#define ROW_PREBUILT_FETCH_MAGIC_N 465765687
#define ROW_PREBUILT_FETCH_MAGIC_N 465765687
...
...
storage/xtradb/row/row0sel.c
View file @
deb3b9a1
...
@@ -58,6 +58,8 @@ Created 12/19/1997 Heikki Tuuri
...
@@ -58,6 +58,8 @@ Created 12/19/1997 Heikki Tuuri
#include "buf0lru.h"
#include "buf0lru.h"
#include "ha_prototypes.h"
#include "ha_prototypes.h"
#include "my_handler.h"
/* enum icp_result */
/* Maximum number of rows to prefetch; MySQL interface has another parameter */
/* Maximum number of rows to prefetch; MySQL interface has another parameter */
#define SEL_MAX_N_PREFETCH 16
#define SEL_MAX_N_PREFETCH 16
...
@@ -2674,59 +2676,42 @@ row_sel_field_store_in_mysql_format(
...
@@ -2674,59 +2676,42 @@ row_sel_field_store_in_mysql_format(
}
}
/**************************************************************//**
/**************************************************************//**
Convert a row in the Innobase format to a row in the MySQL format.
Convert a field in the Innobase format to a field in the MySQL format. */
Note that the template in prebuilt may advise us to copy only a few
columns to mysql_rec, other columns are left blank. All columns may not
be needed in the query.
@return TRUE on success, FALSE if not all columns could be retrieved */
static
__attribute__
((
warn_unused_result
))
static
__attribute__
((
warn_unused_result
))
ibool
ibool
row_sel_store_mysql_rec
(
row_sel_store_mysql_field
(
/*====================*/
/*======================*/
byte
*
mysql_rec
,
/*!< out: row in the MySQL format */
byte
*
mysql_rec
,
/*!< out: record in the
row_prebuilt_t
*
prebuilt
,
/*!< in: prebuilt struct */
MySQL format */
const
rec_t
*
rec
,
/*!< in: Innobase record in the index
row_prebuilt_t
*
prebuilt
,
/*!< in/out: prebuilt struct */
which was described in prebuilt's
const
rec_t
*
rec
,
/*!< in: InnoDB record;
template, or in the clustered index;
must be protected by
must be protected by a page latch */
a page latch */
ibool
rec_clust
,
/*!< in: TRUE if rec is in the
const
ulint
*
offsets
,
/*!< in: array returned by
clustered index instead of
prebuilt->index */
const
ulint
*
offsets
,
/* in: array returned by
rec_get_offsets() */
rec_get_offsets() */
ulint
start_field_no
,
/* in: start from this field */
ulint
field_no
,
/*!< in: templ->rec_field_no or
ulint
end_field_no
)
/* in: end at this field */
templ->clust_rec_field_no */
const
mysql_row_templ_t
*
templ
)
/*!< in: row template */
{
{
mem_heap_t
*
extern_field_heap
=
NULL
;
mem_heap_t
*
heap
;
ulint
i
;
ut_ad
(
prebuilt
->
mysql_template
);
ut_ad
(
prebuilt
->
default_rec
);
ut_ad
(
rec_offs_validate
(
rec
,
NULL
,
offsets
));
ut_ad
(
!
rec_get_deleted_flag
(
rec
,
rec_offs_comp
(
offsets
)));
if
(
UNIV_LIKELY_NULL
(
prebuilt
->
blob_heap
))
{
mem_heap_free
(
prebuilt
->
blob_heap
);
prebuilt
->
blob_heap
=
NULL
;
}
for
(
i
=
start_field_no
;
i
<
end_field_no
/* prebuilt->n_template */
;
i
++
)
{
const
mysql_row_templ_t
*
templ
=
prebuilt
->
mysql_template
+
i
;
const
byte
*
data
;
const
byte
*
data
;
ulint
len
;
ulint
len
;
ulint
field_no
;
field_no
=
rec_clust
ut_ad
(
prebuilt
->
default_rec
);
?
templ
->
clust_rec_field_no
:
templ
->
rec_field_no
;
ut_ad
(
templ
);
ut_ad
(
templ
>=
prebuilt
->
mysql_template
);
ut_ad
(
templ
<
&
prebuilt
->
mysql_template
[
prebuilt
->
n_template
]);
ut_ad
(
field_no
==
templ
->
clust_rec_field_no
||
field_no
==
templ
->
rec_field_no
||
field_no
==
templ
->
icp_rec_field_no
);
ut_ad
(
rec_offs_validate
(
rec
,
NULL
,
offsets
));
if
(
UNIV_UNLIKELY
(
rec_offs_nth_extern
(
offsets
,
field_no
)))
{
if
(
UNIV_UNLIKELY
(
rec_offs_nth_extern
(
offsets
,
field_no
)))
{
/* Copy an externally stored field to the temporary
mem_heap_t
*
heap
;
heap */
/* Copy an externally stored field to a temporary
heap */
ut_a
(
!
prebuilt
->
trx
->
has_search_latch
);
ut_a
(
!
prebuilt
->
trx
->
has_search_latch
);
ut_ad
(
field_no
==
templ
->
clust_rec_field_no
);
if
(
UNIV_UNLIKELY
(
templ
->
type
==
DATA_BLOB
))
{
if
(
UNIV_UNLIKELY
(
templ
->
type
==
DATA_BLOB
))
{
if
(
prebuilt
->
blob_heap
==
NULL
)
{
if
(
prebuilt
->
blob_heap
==
NULL
)
{
...
@@ -2736,10 +2721,7 @@ row_sel_store_mysql_rec(
...
@@ -2736,10 +2721,7 @@ row_sel_store_mysql_rec(
heap
=
prebuilt
->
blob_heap
;
heap
=
prebuilt
->
blob_heap
;
}
else
{
}
else
{
extern_field_heap
heap
=
mem_heap_create
(
UNIV_PAGE_SIZE
);
=
mem_heap_create
(
UNIV_PAGE_SIZE
);
heap
=
extern_field_heap
;
}
}
/* NOTE: if we are retrieving a big BLOB, we may
/* NOTE: if we are retrieving a big BLOB, we may
...
@@ -2752,76 +2734,127 @@ row_sel_store_mysql_rec(
...
@@ -2752,76 +2734,127 @@ row_sel_store_mysql_rec(
field_no
,
&
len
,
heap
);
field_no
,
&
len
,
heap
);
if
(
UNIV_UNLIKELY
(
!
data
))
{
if
(
UNIV_UNLIKELY
(
!
data
))
{
/* The externally stored field
/* The externally stored field was not written
was not written yet. This
yet. This record should only be seen by
record should only be seen by
recv_recovery_rollback_active() or any
recv_recovery_rollback_active()
TRX_ISO_READ_UNCOMMITTED transactions. */
or any TRX_ISO_READ_UNCOMMITTED
transactions. */
if
(
extern_field
_heap
)
{
if
(
heap
!=
prebuilt
->
blob
_heap
)
{
mem_heap_free
(
extern_field_
heap
);
mem_heap_free
(
heap
);
}
}
ut_a
(
prebuilt
->
trx
->
isolation_level
==
TRX_ISO_READ_UNCOMMITTED
);
return
(
FALSE
);
return
(
FALSE
);
}
}
ut_a
(
len
!=
UNIV_SQL_NULL
);
ut_a
(
len
!=
UNIV_SQL_NULL
);
row_sel_field_store_in_mysql_format
(
mysql_rec
+
templ
->
mysql_col_offset
,
templ
,
data
,
len
);
if
(
heap
!=
prebuilt
->
blob_heap
)
{
mem_heap_free
(
heap
);
}
}
else
{
}
else
{
/* Field is stored in the row. */
/* Field is stored in the row. */
data
=
rec_get_nth_field
(
rec
,
offsets
,
field_no
,
&
len
);
data
=
rec_get_nth_field
(
rec
,
offsets
,
field_no
,
&
len
);
if
(
UNIV_UNLIKELY
(
templ
->
type
==
DATA_BLOB
)
if
(
len
==
UNIV_SQL_NULL
)
{
&&
len
!=
UNIV_SQL_NULL
)
{
/* MySQL assumes that the field for an SQL
NULL value is set to the default value. */
ut_ad
(
templ
->
mysql_null_bit_mask
);
UNIV_MEM_ASSERT_RW
(
prebuilt
->
default_rec
+
templ
->
mysql_col_offset
,
templ
->
mysql_col_len
);
mysql_rec
[
templ
->
mysql_null_byte_offset
]
|=
(
byte
)
templ
->
mysql_null_bit_mask
;
memcpy
(
mysql_rec
+
templ
->
mysql_col_offset
,
(
const
byte
*
)
prebuilt
->
default_rec
+
templ
->
mysql_col_offset
,
templ
->
mysql_col_len
);
return
(
TRUE
);
}
if
(
UNIV_UNLIKELY
(
templ
->
type
==
DATA_BLOB
))
{
/* It is a BLOB field locally stored in the
/* It is a BLOB field locally stored in the
InnoDB record: we MUST copy its contents to
InnoDB record: we MUST copy its contents to
prebuilt->blob_heap here because later code
prebuilt->blob_heap here because
assumes all BLOB values have been copied to a
row_sel_field_store_in_mysql_format() stores a
safe place. */
pointer to the data, and the data passed to us
will be invalid as soon as the
mini-transaction is committed and the page
latch on the clustered index page is
released. */
if
(
prebuilt
->
blob_heap
==
NULL
)
{
if
(
prebuilt
->
blob_heap
==
NULL
)
{
prebuilt
->
blob_heap
=
mem_heap_create
(
prebuilt
->
blob_heap
=
mem_heap_create
(
UNIV_PAGE_SIZE
);
UNIV_PAGE_SIZE
);
}
}
data
=
memcpy
(
mem_heap_alloc
(
data
=
mem_heap_dup
(
prebuilt
->
blob_heap
,
data
,
len
);
prebuilt
->
blob_heap
,
len
),
data
,
len
);
}
}
}
if
(
len
!=
UNIV_SQL_NULL
)
{
row_sel_field_store_in_mysql_format
(
row_sel_field_store_in_mysql_format
(
mysql_rec
+
templ
->
mysql_col_offset
,
mysql_rec
+
templ
->
mysql_col_offset
,
templ
,
data
,
len
);
templ
,
data
,
len
);
/* Cleanup */
if
(
extern_field_heap
)
{
mem_heap_free
(
extern_field_heap
);
extern_field_heap
=
NULL
;
}
}
ut_ad
(
len
!=
UNIV_SQL_NULL
);
if
(
templ
->
mysql_null_bit_mask
)
{
if
(
templ
->
mysql_null_bit_mask
)
{
/* It is a nullable column with a non-NULL
/* It is a nullable column with a non-NULL
value */
value */
mysql_rec
[
templ
->
mysql_null_byte_offset
]
mysql_rec
[
templ
->
mysql_null_byte_offset
]
&=
~
(
byte
)
templ
->
mysql_null_bit_mask
;
&=
~
(
byte
)
templ
->
mysql_null_bit_mask
;
}
}
}
else
{
/* MySQL assumes that the field for an SQL
NULL value is set to the default value. */
UNIV_MEM_ASSERT_RW
(
prebuilt
->
default_rec
return
(
TRUE
);
+
templ
->
mysql_col_offset
,
}
templ
->
mysql_col_len
);
mysql_rec
[
templ
->
mysql_null_byte_offset
]
/**************************************************************//**
|=
(
byte
)
templ
->
mysql_null_bit_mask
;
Convert a row in the Innobase format to a row in the MySQL format.
memcpy
(
mysql_rec
+
templ
->
mysql_col_offset
,
Note that the template in prebuilt may advise us to copy only a few
(
const
byte
*
)
prebuilt
->
default_rec
columns to mysql_rec, other columns are left blank. All columns may not
+
templ
->
mysql_col_offset
,
be needed in the query.
templ
->
mysql_col_len
);
@return TRUE on success, FALSE if not all columns could be retrieved */
static
__attribute__
((
warn_unused_result
))
ibool
row_sel_store_mysql_rec
(
/*====================*/
byte
*
mysql_rec
,
/*!< out: row in the MySQL format */
row_prebuilt_t
*
prebuilt
,
/*!< in: prebuilt struct */
const
rec_t
*
rec
,
/*!< in: Innobase record in the index
which was described in prebuilt's
template, or in the clustered index;
must be protected by a page latch */
ibool
rec_clust
,
/*!< in: TRUE if rec is in the
clustered index instead of
prebuilt->index */
const
ulint
*
offsets
)
/*!< in: array returned by
rec_get_offsets(rec) */
{
ulint
i
;
if
(
UNIV_LIKELY_NULL
(
prebuilt
->
blob_heap
))
{
mem_heap_free
(
prebuilt
->
blob_heap
);
prebuilt
->
blob_heap
=
NULL
;
}
for
(
i
=
0
;
i
<
prebuilt
->
n_template
;
i
++
)
{
const
mysql_row_templ_t
*
templ
=
&
prebuilt
->
mysql_template
[
i
];
if
(
!
row_sel_store_mysql_field
(
mysql_rec
,
prebuilt
,
rec
,
offsets
,
rec_clust
?
templ
->
clust_rec_field_no
:
templ
->
rec_field_no
,
templ
))
{
return
(
FALSE
);
}
}
}
}
...
@@ -3192,31 +3225,19 @@ UNIV_INLINE __attribute__((warn_unused_result))
...
@@ -3192,31 +3225,19 @@ UNIV_INLINE __attribute__((warn_unused_result))
ibool
ibool
row_sel_push_cache_row_for_mysql
(
row_sel_push_cache_row_for_mysql
(
/*=============================*/
/*=============================*/
row_prebuilt_t
*
prebuilt
,
/*!< in: prebuilt struct */
byte
*
mysql_rec
,
/*!< in/out: MySQL record */
const
rec_t
*
rec
,
/*!< in: record to push, in the index
row_prebuilt_t
*
prebuilt
)
/*!< in/out: prebuilt struct */
which was described in prebuilt's
template, or in the clustered index;
must be protected by a page latch */
ibool
rec_clust
,
/*!< in: TRUE if rec is in the
clustered index instead of
prebuilt->index */
const
ulint
*
offsets
,
/* in: rec_get_offsets() */
ulint
start_field_no
,
/* in: start from this field */
byte
*
remainder_buf
)
/* in: if start_field_no !=0,
where to take prev fields */
{
{
byte
*
buf
;
ulint
i
;
ut_ad
(
prebuilt
->
n_fetch_cached
<
MYSQL_FETCH_CACHE_SIZE
);
ut_ad
(
prebuilt
->
n_fetch_cached
<
MYSQL_FETCH_CACHE_SIZE
);
ut_ad
(
rec_offs_validate
(
rec
,
NULL
,
offsets
));
ut_ad
(
!
rec_get_deleted_flag
(
rec
,
rec_offs_comp
(
offsets
)));
ut_a
(
!
prebuilt
->
templ_contains_blob
);
ut_a
(
!
prebuilt
->
templ_contains_blob
);
if
(
prebuilt
->
fetch_cache
[
0
]
==
NULL
)
{
if
(
UNIV_UNLIKELY
(
prebuilt
->
fetch_cache
[
0
]
==
NULL
))
{
ulint
i
;
/* Allocate memory for the fetch cache */
/* Allocate memory for the fetch cache */
ut_ad
(
prebuilt
->
n_fetch_cached
==
0
);
for
(
i
=
0
;
i
<
MYSQL_FETCH_CACHE_SIZE
;
i
++
)
{
for
(
i
=
0
;
i
<
MYSQL_FETCH_CACHE_SIZE
;
i
++
)
{
byte
*
buf
;
/* A user has reported memory corruption in these
/* A user has reported memory corruption in these
buffers in Linux. Put magic numbers there to help
buffers in Linux. Put magic numbers there to help
...
@@ -3236,46 +3257,14 @@ row_sel_push_cache_row_for_mysql(
...
@@ -3236,46 +3257,14 @@ row_sel_push_cache_row_for_mysql(
UNIV_MEM_INVALID
(
prebuilt
->
fetch_cache
[
prebuilt
->
n_fetch_cached
],
UNIV_MEM_INVALID
(
prebuilt
->
fetch_cache
[
prebuilt
->
n_fetch_cached
],
prebuilt
->
mysql_row_len
);
prebuilt
->
mysql_row_len
);
if
(
UNIV_UNLIKELY
(
!
row_sel_store_mysql_rec
(
memcpy
(
prebuilt
->
fetch_cache
[
prebuilt
->
n_fetch_cached
],
prebuilt
->
fetch_cache
[
mysql_rec
,
prebuilt
->
mysql_row_len
);
prebuilt
->
n_fetch_cached
],
prebuilt
,
rec
,
rec_clust
,
offsets
,
start_field_no
,
prebuilt
->
n_template
)))
{
return
(
FALSE
);
}
if
(
start_field_no
)
{
if
(
++
prebuilt
->
n_fetch_cached
<
MYSQL_FETCH_CACHE_SIZE
)
{
return
(
FALSE
);
for
(
i
=
0
;
i
<
start_field_no
;
i
++
)
{
register
ulint
offs
;
mysql_row_templ_t
*
templ
;
register
byte
*
null_byte
;
templ
=
prebuilt
->
mysql_template
+
i
;
if
(
templ
->
mysql_null_bit_mask
)
{
offs
=
templ
->
mysql_null_byte_offset
;
null_byte
=
prebuilt
->
fetch_cache
[
prebuilt
->
n_fetch_cached
]
+
offs
;
(
*
null_byte
)
&=
~
templ
->
mysql_null_bit_mask
;
(
*
null_byte
)
|=
(
*
(
remainder_buf
+
offs
)
&
templ
->
mysql_null_bit_mask
);
}
offs
=
templ
->
mysql_col_offset
;
memcpy
(
prebuilt
->
fetch_cache
[
prebuilt
->
n_fetch_cached
]
+
offs
,
remainder_buf
+
offs
,
templ
->
mysql_col_len
);
}
}
}
prebuilt
->
n_fetch_cached
++
;
row_sel_pop_cached_row_for_mysql
(
mysql_rec
,
prebuilt
)
;
return
(
TRUE
);
return
(
TRUE
);
}
}
...
@@ -3353,6 +3342,81 @@ row_sel_try_search_shortcut_for_mysql(
...
@@ -3353,6 +3342,81 @@ row_sel_try_search_shortcut_for_mysql(
return
(
SEL_FOUND
);
return
(
SEL_FOUND
);
}
}
/*********************************************************************//**
Check a pushed-down index condition.
@return ICP_NO_MATCH, ICP_MATCH, or ICP_OUT_OF_RANGE */
static
enum
icp_result
row_search_idx_cond_check
(
/*======================*/
byte
*
mysql_rec
,
/*!< out: record
in MySQL format (invalid unless
prebuilt->idx_cond!=NULL and
we return ICP_MATCH) */
row_prebuilt_t
*
prebuilt
,
/*!< in/out: prebuilt struct
for the table handle */
const
rec_t
*
rec
,
/*!< in: InnoDB record */
const
ulint
*
offsets
)
/*!< in: rec_get_offsets() */
{
enum
icp_result
result
;
ulint
i
;
ut_ad
(
rec_offs_validate
(
rec
,
prebuilt
->
index
,
offsets
));
if
(
!
prebuilt
->
idx_cond
)
{
return
(
ICP_MATCH
);
}
/* Convert to MySQL format those fields that are needed for
evaluating the index condition. */
if
(
UNIV_LIKELY_NULL
(
prebuilt
->
blob_heap
))
{
mem_heap_empty
(
prebuilt
->
blob_heap
);
}
for
(
i
=
0
;
i
<
prebuilt
->
idx_cond_n_cols
;
i
++
)
{
const
mysql_row_templ_t
*
templ
=
&
prebuilt
->
mysql_template
[
i
];
if
(
!
row_sel_store_mysql_field
(
mysql_rec
,
prebuilt
,
rec
,
offsets
,
templ
->
icp_rec_field_no
,
templ
))
{
return
(
ICP_NO_MATCH
);
}
}
/* We assume that the index conditions on
case-insensitive columns are case-insensitive. The
case of such columns may be wrong in a secondary
index, if the case of the column has been updated in
the past, or a record has been deleted and a record
inserted in a different case. */
result
=
innobase_index_cond
(
prebuilt
->
idx_cond
);
switch
(
result
)
{
case
ICP_MATCH
:
/* Convert the remaining fields to MySQL format.
If this is a secondary index record, we must defer
this until we have fetched the clustered index record. */
if
(
!
prebuilt
->
need_to_access_clustered
||
dict_index_is_clust
(
prebuilt
->
index
))
{
if
(
!
row_sel_store_mysql_rec
(
mysql_rec
,
prebuilt
,
rec
,
FALSE
,
offsets
))
{
ut_ad
(
dict_index_is_clust
(
prebuilt
->
index
));
result
=
ICP_NO_MATCH
;
}
}
/* fall through */
case
ICP_NO_MATCH
:
case
ICP_OUT_OF_RANGE
:
case
ICP_ABORTED_BY_USER
:
return
(
result
);
default:
;
}
ut_error
;
}
/********************************************************************//**
/********************************************************************//**
Searches for rows in the database. This is used in the interface to
Searches for rows in the database. This is used in the interface to
MySQL. This function opens a cursor, and also implements fetch next
MySQL. This function opens a cursor, and also implements fetch next
...
@@ -3415,10 +3479,8 @@ row_search_for_mysql(
...
@@ -3415,10 +3479,8 @@ row_search_for_mysql(
mem_heap_t
*
heap
=
NULL
;
mem_heap_t
*
heap
=
NULL
;
ulint
offsets_
[
REC_OFFS_NORMAL_SIZE
];
ulint
offsets_
[
REC_OFFS_NORMAL_SIZE
];
ulint
*
offsets
=
offsets_
;
ulint
*
offsets
=
offsets_
;
ibool
some_fields_in_buffer
;
ibool
table_lock_waited
=
FALSE
;
ibool
table_lock_waited
=
FALSE
;
ibool
problematic_use
=
FALSE
;
ibool
problematic_use
=
FALSE
;
ibool
get_clust_rec
=
0
;
rec_offs_init
(
offsets_
);
rec_offs_init
(
offsets_
);
...
@@ -3681,10 +3743,24 @@ row_search_for_mysql(
...
@@ -3681,10 +3743,24 @@ row_search_for_mysql(
mtr_commit(&mtr). */
mtr_commit(&mtr). */
ut_ad
(
!
rec_get_deleted_flag
(
rec
,
comp
));
ut_ad
(
!
rec_get_deleted_flag
(
rec
,
comp
));
if
(
prebuilt
->
idx_cond
)
{
switch
(
row_search_idx_cond_check
(
buf
,
prebuilt
,
rec
,
offsets
))
{
case
ICP_NO_MATCH
:
case
ICP_OUT_OF_RANGE
:
case
ICP_ABORTED_BY_USER
:
goto
shortcut_mismatch
;
case
ICP_MATCH
:
goto
shortcut_match
;
default:
;
}
ut_error
;
}
if
(
!
row_sel_store_mysql_rec
(
buf
,
prebuilt
,
if
(
!
row_sel_store_mysql_rec
(
buf
,
prebuilt
,
rec
,
FALSE
,
rec
,
FALSE
,
offsets
,
0
,
offsets
))
{
prebuilt
->
n_template
))
{
/* Only fresh inserts may contain
/* Only fresh inserts may contain
incomplete externally stored
incomplete externally stored
columns. Pretend that such
columns. Pretend that such
...
@@ -3695,13 +3771,12 @@ row_search_for_mysql(
...
@@ -3695,13 +3771,12 @@ row_search_for_mysql(
rolling back a recovered
rolling back a recovered
transaction. Rollback happens
transaction. Rollback happens
at a lower level, not here. */
at a lower level, not here. */
ut_a
(
trx
->
isolation_level
==
TRX_ISO_READ_UNCOMMITTED
);
/* Proceed as in case SEL_RETRY. */
/* Proceed as in case SEL_RETRY. */
break
;
break
;
}
}
shortcut_match:
mtr_commit
(
&
mtr
);
mtr_commit
(
&
mtr
);
/* ut_print_name(stderr, index->name);
/* ut_print_name(stderr, index->name);
...
@@ -3713,6 +3788,7 @@ row_search_for_mysql(
...
@@ -3713,6 +3788,7 @@ row_search_for_mysql(
goto
release_search_latch_if_needed
;
goto
release_search_latch_if_needed
;
case
SEL_EXHAUSTED
:
case
SEL_EXHAUSTED
:
shortcut_mismatch:
mtr_commit
(
&
mtr
);
mtr_commit
(
&
mtr
);
/* ut_print_name(stderr, index->name);
/* ut_print_name(stderr, index->name);
...
@@ -3804,8 +3880,9 @@ row_search_for_mysql(
...
@@ -3804,8 +3880,9 @@ row_search_for_mysql(
if
(
!
prebuilt
->
sql_stat_start
)
{
if
(
!
prebuilt
->
sql_stat_start
)
{
/* No need to set an intention lock or assign a read view */
/* No need to set an intention lock or assign a read view */
if
(
trx
->
read_view
==
NULL
if
(
UNIV_UNLIKELY
&&
prebuilt
->
select_lock_type
==
LOCK_NONE
)
{
(
trx
->
read_view
==
NULL
&&
prebuilt
->
select_lock_type
==
LOCK_NONE
))
{
fputs
(
"InnoDB: Error: MySQL is trying to"
fputs
(
"InnoDB: Error: MySQL is trying to"
" perform a consistent read
\n
"
" perform a consistent read
\n
"
...
@@ -4265,6 +4342,16 @@ row_search_for_mysql(
...
@@ -4265,6 +4342,16 @@ row_search_for_mysql(
if
(
UNIV_LIKELY
(
trx
->
wait_lock
!=
NULL
))
{
if
(
UNIV_LIKELY
(
trx
->
wait_lock
!=
NULL
))
{
lock_cancel_waiting_and_release
(
lock_cancel_waiting_and_release
(
trx
->
wait_lock
);
trx
->
wait_lock
);
mutex_exit
(
&
kernel_mutex
);
if
(
old_vers
==
NULL
)
{
/* The row was not yet committed */
goto
next_rec
;
}
did_semi_consistent_read
=
TRUE
;
rec
=
old_vers
;
}
else
{
}
else
{
mutex_exit
(
&
kernel_mutex
);
mutex_exit
(
&
kernel_mutex
);
...
@@ -4275,19 +4362,7 @@ row_search_for_mysql(
...
@@ -4275,19 +4362,7 @@ row_search_for_mysql(
offsets
=
rec_get_offsets
(
rec
,
index
,
offsets
,
offsets
=
rec_get_offsets
(
rec
,
index
,
offsets
,
ULINT_UNDEFINED
,
ULINT_UNDEFINED
,
&
heap
);
&
heap
);
err
=
DB_SUCCESS
;
break
;
}
mutex_exit
(
&
kernel_mutex
);
if
(
old_vers
==
NULL
)
{
/* The row was not yet committed */
goto
next_rec
;
}
}
did_semi_consistent_read
=
TRUE
;
rec
=
old_vers
;
break
;
break
;
default:
default:
...
@@ -4346,8 +4421,27 @@ row_search_for_mysql(
...
@@ -4346,8 +4421,27 @@ row_search_for_mysql(
if
(
!
lock_sec_rec_cons_read_sees
(
if
(
!
lock_sec_rec_cons_read_sees
(
rec
,
trx
->
read_view
))
{
rec
,
trx
->
read_view
))
{
get_clust_rec
=
TRUE
;
/* We should look at the clustered index.
goto
idx_cond_check
;
However, as this is a non-locking read,
we can skip the clustered index lookup if
the condition does not match the secondary
index entry. */
switch
(
row_search_idx_cond_check
(
buf
,
prebuilt
,
rec
,
offsets
))
{
case
ICP_NO_MATCH
:
goto
next_rec
;
case
ICP_OUT_OF_RANGE
:
err
=
DB_RECORD_NOT_FOUND
;
goto
idx_cond_failed
;
case
ICP_ABORTED_BY_USER
:
err
=
DB_SEARCH_ABORTED_BY_USER
;
goto
idx_cond_failed
;
case
ICP_MATCH
:
goto
requires_clust_rec
;
default:
;
}
ut_error
;
}
}
}
}
}
}
...
@@ -4392,38 +4486,31 @@ row_search_for_mysql(
...
@@ -4392,38 +4486,31 @@ row_search_for_mysql(
goto
next_rec
;
goto
next_rec
;
}
}
/* Check if the record matches the index condition. */
idx_cond_check:
switch
(
row_search_idx_cond_check
(
buf
,
prebuilt
,
rec
,
offsets
))
{
if
(
prebuilt
->
idx_cond_func
)
{
case
ICP_NO_MATCH
:
int
res
;
if
(
did_semi_consistent_read
)
{
ibool
ib_res
;
row_unlock_for_mysql
(
prebuilt
,
TRUE
);
ut_ad
(
prebuilt
->
template_type
!=
ROW_MYSQL_DUMMY_TEMPLATE
);
}
offsets
=
rec_get_offsets
(
rec
,
index
,
offsets
,
ULINT_UNDEFINED
,
&
heap
);
ib_res
=
row_sel_store_mysql_rec
(
buf
,
prebuilt
,
rec
,
FALSE
,
offsets
,
0
,
prebuilt
->
n_index_fields
);
/*
The above call will fail and return FALSE when requested to
store an "externally stored column" (afaiu, a blob). Index
Condition Pushdown is not supported for indexes with blob
columns, so we should never get this error.
*/
ut_ad
(
ib_res
);
res
=
prebuilt
->
idx_cond_func
(
prebuilt
->
idx_cond_func_arg
);
if
(
res
==
XTRADB_ICP_NO_MATCH
)
goto
next_rec
;
goto
next_rec
;
else
if
(
res
!=
XTRADB_ICP_MATCH
)
{
case
ICP_ABORTED_BY_USER
:
err
=
(
res
==
XTRADB_ICP_ABORTED_BY_USER
?
err
=
DB_SEARCH_ABORTED_BY_USER
;
DB_SEARCH_ABORTED_BY_USER
:
DB_RECORD_NOT_FOUND
);
goto
idx_cond_failed
;
goto
idx_cond_failed
;
}
case
ICP_OUT_OF_RANGE
:
/* res == XTRADB_ICP_MATCH */
err
=
DB_RECORD_NOT_FOUND
;
goto
idx_cond_failed
;
case
ICP_MATCH
:
break
;
default:
ut_error
;
}
}
/* Get the clustered index record if needed, if we did not do the
/* Get the clustered index record if needed, if we did not do the
search using the clustered index. */
search using the clustered index. */
if
(
get_clust_rec
||
(
index
!=
clust_index
if
(
index
!=
clust_index
&&
prebuilt
->
need_to_access_clustered
)
{
&&
prebuilt
->
need_to_access_clustered
))
{
requires_clust_rec:
ut_ad
(
index
!=
clust_index
);
/* We use a 'goto' to the preceding label if a consistent
/* We use a 'goto' to the preceding label if a consistent
read of a secondary index record requires us to look up old
read of a secondary index record requires us to look up old
...
@@ -4487,6 +4574,19 @@ row_search_for_mysql(
...
@@ -4487,6 +4574,19 @@ row_search_for_mysql(
result_rec
=
clust_rec
;
result_rec
=
clust_rec
;
ut_ad
(
rec_offs_validate
(
result_rec
,
clust_index
,
offsets
));
ut_ad
(
rec_offs_validate
(
result_rec
,
clust_index
,
offsets
));
if
(
prebuilt
->
idx_cond
)
{
/* Convert the remaining fields to
MySQL format. We were unable to do
this in row_search_idx_cond_check(),
because the condition is on the
secondary index and the requested
column is in the clustered index. */
if
(
!
row_sel_store_mysql_rec
(
buf
,
prebuilt
,
result_rec
,
TRUE
,
offsets
))
{
goto
next_rec
;
}
}
}
else
{
}
else
{
result_rec
=
rec
;
result_rec
=
rec
;
}
}
...
@@ -4520,15 +4620,10 @@ row_search_for_mysql(
...
@@ -4520,15 +4620,10 @@ row_search_for_mysql(
are BLOBs in the fields to be fetched. In HANDLER we do
are BLOBs in the fields to be fetched. In HANDLER we do
not cache rows because there the cursor is a scrollable
not cache rows because there the cursor is a scrollable
cursor. */
cursor. */
some_fields_in_buffer
=
(
index
!=
clust_index
&&
prebuilt
->
idx_cond_func
);
if
(
!
prebuilt
->
idx_cond
&&
!
row_sel_store_mysql_rec
(
buf
,
prebuilt
,
result_rec
,
if
(
!
row_sel_push_cache_row_for_mysql
(
prebuilt
,
result_rec
,
result_rec
!=
rec
,
offsets
))
{
result_rec
!=
rec
,
offsets
,
some_fields_in_buffer
?
prebuilt
->
n_index_fields
:
0
,
buf
))
{
/* Only fresh inserts may contain incomplete
/* Only fresh inserts may contain incomplete
externally stored columns. Pretend that such
externally stored columns. Pretend that such
records do not exist. Such records may only be
records do not exist. Such records may only be
...
@@ -4536,14 +4631,10 @@ row_search_for_mysql(
...
@@ -4536,14 +4631,10 @@ row_search_for_mysql(
level or when rolling back a recovered
level or when rolling back a recovered
transaction. Rollback happens at a lower
transaction. Rollback happens at a lower
level, not here. */
level, not here. */
ut_a
(
trx
->
isolation_level
==
TRX_ISO_READ_UNCOMMITTED
);
}
else
if
(
prebuilt
->
n_fetch_cached
==
MYSQL_FETCH_CACHE_SIZE
)
{
goto
got_row
;
}
goto
next_rec
;
goto
next_rec
;
}
else
if
(
row_sel_push_cache_row_for_mysql
(
buf
,
prebuilt
))
{
goto
next_rec
;
}
}
else
{
}
else
{
if
(
UNIV_UNLIKELY
if
(
UNIV_UNLIKELY
(
prebuilt
->
template_type
==
ROW_MYSQL_DUMMY_TEMPLATE
))
{
(
prebuilt
->
template_type
==
ROW_MYSQL_DUMMY_TEMPLATE
))
{
...
@@ -4564,15 +4655,11 @@ row_search_for_mysql(
...
@@ -4564,15 +4655,11 @@ row_search_for_mysql(
rec_offs_size
(
offsets
));
rec_offs_size
(
offsets
));
mach_write_to_4
(
buf
,
mach_write_to_4
(
buf
,
rec_offs_extra_size
(
offsets
)
+
4
);
rec_offs_extra_size
(
offsets
)
+
4
);
}
else
{
}
else
if
(
!
prebuilt
->
idx_cond
)
{
/* Returning a row to MySQL */
/* The record was not yet converted to MySQL format. */
if
(
!
row_sel_store_mysql_rec
(
if
(
!
row_sel_store_mysql_rec
(
buf
,
prebuilt
,
result_rec
,
buf
,
prebuilt
,
result_rec
!=
rec
,
result_rec
,
result_rec
!=
rec
,
offsets
))
{
offsets
,
prebuilt
->
idx_cond_func
?
prebuilt
->
n_index_fields
:
0
,
prebuilt
->
n_template
))
{
/* Only fresh inserts may contain
/* Only fresh inserts may contain
incomplete externally stored
incomplete externally stored
columns. Pretend that such records do
columns. Pretend that such records do
...
@@ -4581,8 +4668,6 @@ row_search_for_mysql(
...
@@ -4581,8 +4668,6 @@ row_search_for_mysql(
isolation level or when rolling back a
isolation level or when rolling back a
recovered transaction. Rollback
recovered transaction. Rollback
happens at a lower level, not here. */
happens at a lower level, not here. */
ut_a
(
trx
->
isolation_level
==
TRX_ISO_READ_UNCOMMITTED
);
goto
next_rec
;
goto
next_rec
;
}
}
}
}
...
@@ -4600,7 +4685,6 @@ row_search_for_mysql(
...
@@ -4600,7 +4685,6 @@ row_search_for_mysql(
/* From this point on, 'offsets' are invalid. */
/* From this point on, 'offsets' are invalid. */
got_row:
/* We have an optimization to save CPU time: if this is a consistent
/* We have an optimization to save CPU time: if this is a consistent
read on a unique condition on the clustered index, then we do not
read on a unique condition on the clustered index, then we do not
store the pcur position, because any fetch next or prev will anyway
store the pcur position, because any fetch next or prev will anyway
...
@@ -4624,7 +4708,6 @@ row_search_for_mysql(
...
@@ -4624,7 +4708,6 @@ row_search_for_mysql(
next_rec:
next_rec:
/* Reset the old and new "did semi-consistent read" flags. */
/* Reset the old and new "did semi-consistent read" flags. */
get_clust_rec
=
FALSE
;
if
(
UNIV_UNLIKELY
(
prebuilt
->
row_read_type
if
(
UNIV_UNLIKELY
(
prebuilt
->
row_read_type
==
ROW_READ_DID_SEMI_CONSISTENT
))
{
==
ROW_READ_DID_SEMI_CONSISTENT
))
{
prebuilt
->
row_read_type
=
ROW_READ_TRY_SEMI_CONSISTENT
;
prebuilt
->
row_read_type
=
ROW_READ_TRY_SEMI_CONSISTENT
;
...
@@ -4635,6 +4718,7 @@ row_search_for_mysql(
...
@@ -4635,6 +4718,7 @@ row_search_for_mysql(
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
/* PHASE 5: Move the cursor to the next index record */
/* PHASE 5: Move the cursor to the next index record */
/*TODO: with ICP, do this when switching pages, every N pages */
if
(
UNIV_UNLIKELY
(
mtr_has_extra_clust_latch
))
{
if
(
UNIV_UNLIKELY
(
mtr_has_extra_clust_latch
))
{
/* We must commit mtr if we are moving to the next
/* We must commit mtr if we are moving to the next
non-clustered index record, because we could break the
non-clustered index record, because we could break the
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment