Merge bk@192.168.21.1:mysql-5.1

into  mysql.com:/home/hf/work/mrg/mysql-5.1-opt


sql/mysqld.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
This commit is contained in:
unknown 2007-03-16 11:54:36 +04:00
commit cf2842b56d
40 changed files with 1066 additions and 304 deletions

View file

@ -881,6 +881,42 @@ create table t1 (t varchar(255) default null, key t (t(80)))
engine=myisam default charset=latin1;
alter table t1 change t t text;
drop table t1;
CREATE TABLE t1 (a varchar(500));
ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(500) DEFAULT NULL,
`b` geometry NOT NULL,
SPATIAL KEY `b` (`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 ADD KEY(b(50));
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(500) DEFAULT NULL,
`b` geometry NOT NULL,
SPATIAL KEY `b` (`b`),
KEY `b_2` (`b`(50))
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 ADD c POINT;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(500) DEFAULT NULL,
`b` geometry NOT NULL,
`c` point DEFAULT NULL,
SPATIAL KEY `b` (`b`),
KEY `b_2` (`b`(50))
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE TABLE t2 (a INT, KEY (a(20)));
ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys
ALTER TABLE t1 ADD d INT;
ALTER TABLE t1 ADD KEY (d(20));
ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys
ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30));
ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys
DROP TABLE t1;
CREATE TABLE t1 (s CHAR(8) BINARY);
INSERT INTO t1 VALUES ('test');
SELECT LENGTH(s) FROM t1;

View file

@ -25,10 +25,11 @@ insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
text1
teststring
teststring
teststring
select * from t1 where text1='teststring' or text1 like 'teststring_%';
text1
teststring
@ -48,10 +49,11 @@ alter table t1 modify text1 char(32) binary not null;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
text1
teststring
teststring
teststring
select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
concat('|', text1, '|')
|teststring |
@ -132,10 +134,11 @@ concat('|', text1, '|')
drop table t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap;
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
text1
teststring
teststring
teststring
select * from t1 where text1='teststring' or text1 like 'teststring_%';
text1
teststring

View file

@ -1,26 +1,12 @@
flush logs;
set global expire_logs_days = 3;
show variables like 'log%';
show variables like 'log_bin%';
Variable_name Value
log ON
log_bin OFF
log_bin_trust_function_creators ON
log_error
log_output TABLE
log_queries_not_using_indexes OFF
log_slave_updates OFF
log_slow_queries OFF
log_warnings 1
flush logs;
show variables like 'log%';
show variables like 'log_bin%';
Variable_name Value
log ON
log_bin OFF
log_bin_trust_function_creators ON
log_error
log_output TABLE
log_queries_not_using_indexes OFF
log_slave_updates OFF
log_slow_queries OFF
log_warnings 1
set global expire_logs_days = 0;

View file

@ -10,7 +10,7 @@ t1 CREATE TABLE `t1` (
`fid` int(11) NOT NULL AUTO_INCREMENT,
`g` geometry NOT NULL,
PRIMARY KEY (`fid`),
SPATIAL KEY `g` (`g`(32))
SPATIAL KEY `g` (`g`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)'));
@ -293,7 +293,7 @@ t2 CREATE TABLE `t2` (
`fid` int(11) NOT NULL AUTO_INCREMENT,
`g` geometry NOT NULL,
PRIMARY KEY (`fid`),
SPATIAL KEY `g` (`g`(32))
SPATIAL KEY `g` (`g`)
) ENGINE=MyISAM AUTO_INCREMENT=101 DEFAULT CHARSET=latin1
SELECT count(*) FROM t2;
count(*)
@ -803,7 +803,7 @@ CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom));
INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
drop table t1, t2;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`(32))) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Warnings:
Warning 1101 BLOB/TEXT column 'geometry' can't have a default value
INSERT INTO t1 (geometry) VALUES
@ -820,7 +820,7 @@ test.t1 check status OK
drop table t1;
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Warnings:
Warning 1101 BLOB/TEXT column 'c1' can't have a default value
@ -836,7 +836,7 @@ test.t1 check status OK
DROP TABLE t1;
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Warnings:
Warning 1101 BLOB/TEXT column 'c1' can't have a default value
@ -879,7 +879,7 @@ c1 varchar(15) collate utf8_bin default NULL,
c3 varchar(10) collate utf8_bin default NULL,
spatial_point point NOT NULL,
PRIMARY KEY(id),
SPATIAL KEY (spatial_point(32))
SPATIAL KEY (spatial_point)
)ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
('y', 's', 'j', GeomFromText('POINT(167 74)')),

View file

@ -1035,12 +1035,110 @@ HAVING SUM(t1_inner.b)+t1_outer.b > 5);
ERROR 42000: 'test.t1_outer.b' isn't in GROUP BY
DROP TABLE t1;
SET SQL_MODE = '';
CREATE TABLE t1 (a INT, b INT, KEY(a));
INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4);
EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2;
CREATE TABLE t1 (a INT, b INT,
PRIMARY KEY (a),
KEY i2(a,b));
INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);
INSERT INTO t1 SELECT a + 8,b FROM t1;
INSERT INTO t1 SELECT a + 16,b FROM t1;
INSERT INTO t1 SELECT a + 32,b FROM t1;
INSERT INTO t1 SELECT a + 64,b FROM t1;
INSERT INTO t1 SELECT a + 128,b FROM t1;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
EXPLAIN SELECT a FROM t1 WHERE a < 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 5 NULL 4
EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2;
1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index
EXPLAIN SELECT a FROM t1 WHERE a < 2 ORDER BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
DROP TABLE t1;
1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index
EXPLAIN SELECT a FROM t1 WHERE a < 2 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY,i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index; Using filesort
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY) IGNORE INDEX FOR ORDER BY (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 FORCE INDEX (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 USE INDEX ();
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 USE INDEX () USE INDEX (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1
FORCE INDEX (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2)
IGNORE INDEX FOR ORDER BY (i2)
USE INDEX (i2);
ERROR HY000: Incorrect usage of USE INDEX and FORCE INDEX
EXPLAIN SELECT a FROM t1 USE INDEX (i2) USE INDEX ();
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 FORCE INDEX ();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
EXPLAIN SELECT a FROM t1 IGNORE INDEX ();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1
EXPLAIN SELECT a FROM t1 USE INDEX FOR JOIN (i2)
USE INDEX FOR GROUP BY (i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1 FORCE INDEX FOR JOIN (i2)
FORCE INDEX FOR GROUP BY (i2) GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL i2 4 NULL 257 Using index for group-by
EXPLAIN SELECT a FROM t1 USE INDEX () IGNORE INDEX (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1 IGNORE INDEX (i2) USE INDEX ();
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 256
EXPLAIN SELECT a FROM t1
USE INDEX FOR GROUP BY (i2)
USE INDEX FOR ORDER BY (i2)
USE INDEX FOR JOIN (i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT a FROM t1
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2,i2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i2 9 NULL 256 Using index
EXPLAIN SELECT 1 FROM t1 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 256 Using where; Using index
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where
CREATE TABLE t2 (a INT, b INT, KEY(a));
INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4);
EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL a 5 NULL 4
EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
EXPLAIN SELECT 1 FROM t2 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where
DROP TABLE t1, t2;

View file

@ -489,3 +489,44 @@ EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
drop table t1;
CREATE TABLE t1 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c INTEGER NOT NULL,
d CHAR(64)
);
CREATE TABLE t2 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c SMALLINT NOT NULL,
d DATETIME NOT NULL,
e SMALLINT NOT NULL,
f INTEGER NOT NULL,
g INTEGER NOT NULL,
h SMALLINT NOT NULL,
i INTEGER NOT NULL,
j INTEGER NOT NULL,
UNIQUE INDEX (b),
INDEX (b, d, e, f, g, h, i, j, c),
INDEX (c)
);
INSERT INTO t2 VALUES
(NULL, 1, 254, '1000-01-01 00:00:00', 257, 0, 0, 0, 0, 0),
(NULL, 2, 1, '2004-11-30 12:00:00', 1, 0, 0, 0, 0, 0),
(NULL, 3, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -21600, 0),
(NULL, 4, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -10800, 0),
(NULL, 5, 1, '2004-11-30 12:00:00', 1, 0, 0, 5, -10800, 0),
(NULL, 6, 1, '2004-11-30 12:00:00', 102, 0, 0, 0, 0, 0),
(NULL, 7, 1, '2004-11-30 12:00:00', 105, 2, 0, 0, 0, 0),
(NULL, 8, 1, '2004-11-30 12:00:00', 105, 10, 0, 0, 0, 0);
INSERT INTO t1 (b, c, d) VALUES
(3388000, -553000, NULL),
(3388000, -553000, NULL);
SELECT *
FROM t2 c JOIN t1 pa ON c.b = pa.a
WHERE c.c = 1
ORDER BY c.b, c.d
;
a b c d e f g h i j a b c d
2 2 1 2004-11-30 12:00:00 1 0 0 0 0 0 2 3388000 -553000 NULL
DROP TABLE t1, t2;

View file

@ -958,6 +958,28 @@ a ratio
19 1.3333
9 2.6667
drop table t1;
CREATE TABLE t1 (a INT UNSIGNED NOT NULL, b TIME);
INSERT INTO t1 (a) VALUES (100000), (0), (100), (1000000),(10000), (1000), (10);
UPDATE t1 SET b = SEC_TO_TIME(a);
SELECT a, b FROM t1 ORDER BY b DESC;
a b
1000000 277:46:40
100000 27:46:40
10000 02:46:40
1000 00:16:40
100 00:01:40
10 00:00:10
0 00:00:00
SELECT a, b FROM t1 ORDER BY SEC_TO_TIME(a) DESC;
a b
1000000 277:46:40
100000 27:46:40
10000 02:46:40
1000 00:16:40
100 00:01:40
10 00:00:10
0 00:00:00
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a), UNIQUE KEY b (b));
INSERT INTO t1 VALUES (1,1),(2,2);
CREATE TABLE t2 (a INT, b INT, KEY a (a,b));

View file

@ -3933,4 +3933,42 @@ cc cc 7
aa aa 2
aa aa 2
DROP TABLE t1,t2;
CREATE TABLE t1 (
access_id int NOT NULL default '0',
name varchar(20) default NULL,
rank int NOT NULL default '0',
KEY idx (access_id)
);
CREATE TABLE t2 (
faq_group_id int NOT NULL default '0',
faq_id int NOT NULL default '0',
access_id int default NULL,
UNIQUE KEY idx1 (faq_id),
KEY idx2 (faq_group_id,faq_id)
);
INSERT INTO t1 VALUES
(1,'Everyone',2),(2,'Help',3),(3,'Technical Support',1),(4,'Chat User',4);
INSERT INTO t2 VALUES
(261,265,1),(490,494,1);
SELECT t2.faq_id
FROM t1 INNER JOIN t2 IGNORE INDEX (idx1)
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
faq_id
265
SELECT t2.faq_id
FROM t1 INNER JOIN t2
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
faq_id
265
DROP TABLE t1,t2;
End of 5.0 tests

View file

@ -3873,3 +3873,16 @@ id_1
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t1xt2;
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (3), (1), (2);
SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1;
col1 col2
this is a test. 3
this is a test. 1
this is a test. 2
SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t;
col1 t2
this is a test. 3
this is a test. 1
this is a test. 2
DROP table t1;

View file

@ -641,6 +641,33 @@ engine=myisam default charset=latin1;
alter table t1 change t t text;
drop table t1;
#
# Bug #26794: Adding an index with a prefix on a SPATIAL type breaks ALTER
# TABLE
#
CREATE TABLE t1 (a varchar(500));
ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b);
SHOW CREATE TABLE t1;
ALTER TABLE t1 ADD KEY(b(50));
SHOW CREATE TABLE t1;
ALTER TABLE t1 ADD c POINT;
SHOW CREATE TABLE t1;
--error ER_WRONG_SUB_KEY
CREATE TABLE t2 (a INT, KEY (a(20)));
ALTER TABLE t1 ADD d INT;
--error ER_WRONG_SUB_KEY
ALTER TABLE t1 ADD KEY (d(20));
# the 5.1 part of the test
--error ER_WRONG_SUB_KEY
ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30));
DROP TABLE t1;
#
# Bug#18038 MySQL server corrupts binary columns data
#

View file

@ -16,7 +16,8 @@ drop table if exists t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 (text1));
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
check table t1;
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
select * from t1 where text1='teststring' or text1 like 'teststring_%';
select * from t1 where text1='teststring' or text1 > 'teststring\t';
select * from t1 order by text1;
@ -24,7 +25,8 @@ explain select * from t1 order by text1;
alter table t1 modify text1 char(32) binary not null;
check table t1;
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t';
select text1, length(text1) from t1 order by text1;
@ -57,7 +59,8 @@ drop table t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap;
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%';
select * from t1 ignore key (key1) where text1='teststring' or
text1 like 'teststring_%' ORDER BY text1;
select * from t1 where text1='teststring' or text1 like 'teststring_%';
select * from t1 where text1='teststring' or text1 >= 'teststring\t';
select * from t1 order by text1;

View file

@ -3,7 +3,7 @@
#
flush logs;
set global expire_logs_days = 3;
show variables like 'log%';
show variables like 'log_bin%';
flush logs;
show variables like 'log%';
show variables like 'log_bin%';
set global expire_logs_days = 0;

View file

@ -172,7 +172,7 @@ CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom));
INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
drop table t1, t2;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`(32))) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1 (geometry) VALUES
(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
@ -192,7 +192,7 @@ drop table t1;
#
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1 (c1) VALUES (
PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
@ -206,7 +206,7 @@ DROP TABLE t1;
#
CREATE TABLE t1 (
c1 geometry NOT NULL default '',
SPATIAL KEY i1 (c1(32))
SPATIAL KEY i1 (c1)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO t1 (c1) VALUES (
PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
@ -251,7 +251,7 @@ CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
c3 varchar(10) collate utf8_bin default NULL,
spatial_point point NOT NULL,
PRIMARY KEY(id),
SPATIAL KEY (spatial_point(32))
SPATIAL KEY (spatial_point)
)ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
#
INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES

View file

@ -757,10 +757,66 @@ SET SQL_MODE = '';
# Bug #21174: Index degrades sort performance and
# optimizer does not honor IGNORE INDEX
#
CREATE TABLE t1 (a INT, b INT, KEY(a));
INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4);
CREATE TABLE t1 (a INT, b INT,
PRIMARY KEY (a),
KEY i2(a,b));
INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8);
INSERT INTO t1 SELECT a + 8,b FROM t1;
INSERT INTO t1 SELECT a + 16,b FROM t1;
INSERT INTO t1 SELECT a + 32,b FROM t1;
INSERT INTO t1 SELECT a + 64,b FROM t1;
INSERT INTO t1 SELECT a + 128,b FROM t1;
ANALYZE TABLE t1;
EXPLAIN SELECT a FROM t1 WHERE a < 2;
EXPLAIN SELECT a FROM t1 WHERE a < 2 ORDER BY a;
EXPLAIN SELECT a FROM t1 WHERE a < 2 GROUP BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY,i2);
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2);
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY) IGNORE INDEX FOR ORDER BY (i2);
EXPLAIN SELECT a FROM t1 FORCE INDEX (i2);
EXPLAIN SELECT a FROM t1 USE INDEX ();
EXPLAIN SELECT a FROM t1 USE INDEX () USE INDEX (i2);
--error ER_WRONG_USAGE
EXPLAIN SELECT a FROM t1
FORCE INDEX (PRIMARY)
IGNORE INDEX FOR GROUP BY (i2)
IGNORE INDEX FOR ORDER BY (i2)
USE INDEX (i2);
EXPLAIN SELECT a FROM t1 USE INDEX (i2) USE INDEX ();
--error ER_PARSE_ERROR
EXPLAIN SELECT a FROM t1 FORCE INDEX ();
--error ER_PARSE_ERROR
EXPLAIN SELECT a FROM t1 IGNORE INDEX ();
EXPLAIN SELECT a FROM t1 USE INDEX FOR JOIN (i2)
USE INDEX FOR GROUP BY (i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 FORCE INDEX FOR JOIN (i2)
FORCE INDEX FOR GROUP BY (i2) GROUP BY a;
EXPLAIN SELECT a FROM t1 USE INDEX () IGNORE INDEX (i2);
EXPLAIN SELECT a FROM t1 IGNORE INDEX (i2) USE INDEX ();
EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2;
EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2;
EXPLAIN SELECT a FROM t1
USE INDEX FOR GROUP BY (i2)
USE INDEX FOR ORDER BY (i2)
USE INDEX FOR JOIN (i2);
DROP TABLE t1;
EXPLAIN SELECT a FROM t1
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2)
USE INDEX FOR JOIN (i2,i2);
EXPLAIN SELECT 1 FROM t1 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
CREATE TABLE t2 (a INT, b INT, KEY(a));
INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4);
EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2;
EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2;
EXPLAIN SELECT 1 FROM t2 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
DROP TABLE t1, t2;

View file

@ -453,3 +453,51 @@ ALTER TABLE t1 DISABLE KEYS;
EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a);
drop table t1;
#
# Bug #24778: Innodb: No result when using ORDER BY
#
CREATE TABLE t1 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c INTEGER NOT NULL,
d CHAR(64)
);
CREATE TABLE t2 (
a INTEGER auto_increment PRIMARY KEY,
b INTEGER NOT NULL,
c SMALLINT NOT NULL,
d DATETIME NOT NULL,
e SMALLINT NOT NULL,
f INTEGER NOT NULL,
g INTEGER NOT NULL,
h SMALLINT NOT NULL,
i INTEGER NOT NULL,
j INTEGER NOT NULL,
UNIQUE INDEX (b),
INDEX (b, d, e, f, g, h, i, j, c),
INDEX (c)
);
INSERT INTO t2 VALUES
(NULL, 1, 254, '1000-01-01 00:00:00', 257, 0, 0, 0, 0, 0),
(NULL, 2, 1, '2004-11-30 12:00:00', 1, 0, 0, 0, 0, 0),
(NULL, 3, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -21600, 0),
(NULL, 4, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -10800, 0),
(NULL, 5, 1, '2004-11-30 12:00:00', 1, 0, 0, 5, -10800, 0),
(NULL, 6, 1, '2004-11-30 12:00:00', 102, 0, 0, 0, 0, 0),
(NULL, 7, 1, '2004-11-30 12:00:00', 105, 2, 0, 0, 0, 0),
(NULL, 8, 1, '2004-11-30 12:00:00', 105, 10, 0, 0, 0, 0);
INSERT INTO t1 (b, c, d) VALUES
(3388000, -553000, NULL),
(3388000, -553000, NULL);
SELECT *
FROM t2 c JOIN t1 pa ON c.b = pa.a
WHERE c.c = 1
ORDER BY c.b, c.d
;
DROP TABLE t1, t2;

View file

@ -678,6 +678,21 @@ insert into t1 values (1,2,3), (9,8,3), (19,4,3), (1,4,9);
select a,(sum(b)/sum(c)) as ratio from t1 group by a order by sum(b)/sum(c) asc;
drop table t1;
#
# Bug#26672: Incorrect SEC_TO_TIME() casting in ORDER BY
#
CREATE TABLE t1 (a INT UNSIGNED NOT NULL, b TIME);
INSERT INTO t1 (a) VALUES (100000), (0), (100), (1000000),(10000), (1000), (10);
UPDATE t1 SET b = SEC_TO_TIME(a);
-- Correct ORDER
SELECT a, b FROM t1 ORDER BY b DESC;
-- must be ordered as the above
SELECT a, b FROM t1 ORDER BY SEC_TO_TIME(a) DESC;
DROP TABLE t1;
#
# BUG#16590: Optimized does not do right "const" table pre-read
#

View file

@ -3299,4 +3299,51 @@ SELECT * FROM t1 LEFT JOIN t2 ON t1.name=t2.name;
DROP TABLE t1,t2;
#
# Bug #26963: join with predicates that contain fields from equalities evaluated
# to constants after constant table substitution
#
CREATE TABLE t1 (
access_id int NOT NULL default '0',
name varchar(20) default NULL,
rank int NOT NULL default '0',
KEY idx (access_id)
);
CREATE TABLE t2 (
faq_group_id int NOT NULL default '0',
faq_id int NOT NULL default '0',
access_id int default NULL,
UNIQUE KEY idx1 (faq_id),
KEY idx2 (faq_group_id,faq_id)
);
INSERT INTO t1 VALUES
(1,'Everyone',2),(2,'Help',3),(3,'Technical Support',1),(4,'Chat User',4);
INSERT INTO t2 VALUES
(261,265,1),(490,494,1);
SELECT t2.faq_id
FROM t1 INNER JOIN t2 IGNORE INDEX (idx1)
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
SELECT t2.faq_id
FROM t1 INNER JOIN t2
ON (t1.access_id = t2.access_id)
LEFT JOIN t2 t
ON (t.faq_group_id = t2.faq_group_id AND
find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4'))
WHERE
t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265);
DROP TABLE t1,t2;
--echo End of 5.0 tests

View file

@ -2736,3 +2736,15 @@ DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t1xt2;
#
# Bug #26728: derived table with concatanation of literals in select list
#
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (3), (1), (2);
SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1;
SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t;
DROP table t1;

View file

@ -1015,6 +1015,7 @@ bool Field::type_can_have_key_part(enum enum_field_types type)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_GEOMETRY:
return TRUE;
default:
return FALSE;

View file

@ -1374,7 +1374,10 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
}
else
{
switch ((sortorder->result_type=sortorder->item->result_type())) {
sortorder->result_type= sortorder->item->result_type();
if (sortorder->item->result_as_longlong())
sortorder->result_type= INT_RESULT;
switch (sortorder->result_type) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
set_if_smaller(sortorder->length, thd->variables.max_sort_length);

View file

@ -3907,7 +3907,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
{
/* First usage of column */
table->used_fields++; // Used to optimize loops
table->used_keys.intersect(field->part_of_key);
/* purecov: begin inspected */
table->covering_keys.intersect(field->part_of_key);
/* purecov: end */
}
}
}
@ -4125,7 +4127,9 @@ bool Item_field::set_no_const_sub(byte *arg)
DESCRIPTION
The function returns a pointer to an item that is taken from
the very beginning of the item_equal list which the Item_field
object refers to (belongs to).
object refers to (belongs to) unless item_equal contains a constant
item. In this case the function returns this constant item,
(if the substitution does not require conversion).
If the Item_field object does not refer any Item_equal object
'this' is returned
@ -4134,7 +4138,8 @@ bool Item_field::set_no_const_sub(byte *arg)
of the thransformer method.
RETURN VALUES
pointer to a replacement Item_field if there is a better equal item;
pointer to a replacement Item_field if there is a better equal item or
a pointer to a constant equal item;
this - otherwise.
*/
@ -4142,6 +4147,14 @@ Item *Item_field::replace_equal_field(byte *arg)
{
if (item_equal)
{
Item *const_item= item_equal->get_const();
if (const_item)
{
if (cmp_context != (Item_result)-1 &&
const_item->cmp_context != cmp_context)
return this;
return const_item;
}
Item_field *subst= item_equal->get_first();
if (subst && !field->eq(subst->field))
return subst;

View file

@ -1811,7 +1811,11 @@ public:
str_value.length(), collation.collation);
}
Item *safe_charset_converter(CHARSET_INFO *tocs);
inline void append(char *str, uint length) { str_value.append(str, length); }
inline void append(char *str, uint length)
{
str_value.append(str, length);
max_length= str_value.numchars() * collation.collation->mbmaxlen;
}
void print(String *str);
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}

View file

@ -2021,7 +2021,6 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->const_table= 0;
table->null_row= 0;
table->status= STATUS_NO_RECORD;
table->keys_in_use_for_query= table->s->keys_in_use;
table->maybe_null= table_list->outer_join;
TABLE_LIST *embedding= table_list->embedding;
while (!table->maybe_null && embedding)
@ -2032,6 +2031,8 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->tablenr= tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
table->covering_keys= table->s->keys_for_keyread;
table->merge_keys.clear_all();
}

View file

@ -5031,7 +5031,8 @@ enum options_mysqld
OPT_MERGE,
OPT_THREAD_HANDLING,
OPT_INNODB_ROLLBACK_ON_TIMEOUT,
OPT_SECURE_FILE_PRIV
OPT_SECURE_FILE_PRIV,
OPT_OLD_MODE
};
@ -6262,6 +6263,10 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.net_write_timeout,
(gptr*) &max_system_variables.net_write_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{ "old_mode", OPT_OLD_MODE, "Use compatible behaviour.",
(gptr*) &global_system_variables.old_mode,
(gptr*) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"open_files_limit", OPT_OPEN_FILES_LIMIT,
"If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.",
(gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG,

View file

@ -2111,9 +2111,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.key_parts_end=key_parts;
/* Calculate cost of full index read for the shortest covering index */
if (!head->used_keys.is_clear_all())
if (!head->covering_keys.is_clear_all())
{
int key_for_use= find_shortest_key(head, &head->used_keys);
int key_for_use= find_shortest_key(head, &head->covering_keys);
double key_read_time= (get_index_only_read_time(&param, records,
key_for_use) +
(double) records / TIME_FOR_COMPARE);
@ -4646,7 +4646,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
param->needed_reg->set_bit(keynr);
bool read_index_only= index_read_must_be_used ? TRUE :
(bool) param->table->used_keys.is_set(keynr);
(bool) param->table->covering_keys.is_set(keynr);
found_records= check_quick_select(param, idx, *key, update_tbl_stats);
if (param->is_ror_scan)
@ -9012,7 +9012,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
cur_index_info++, cur_index++)
{
/* Check (B1) - if current index is covering. */
if (!table->used_keys.is_set(cur_index))
if (!table->covering_keys.is_set(cur_index))
goto next_index;
/*

View file

@ -1851,8 +1851,6 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
table->const_table=0;
table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= share->keys_in_use;
table->used_keys= share->keys_for_keyread;
DBUG_RETURN(FALSE);
}
@ -2271,9 +2269,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->const_table=0;
table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->s->keys_in_use;
table->insert_values= 0;
table->used_keys= table->s->keys_for_keyread;
table->fulltext_searched= 0;
table->file->ft_handler= 0;
if (table->timestamp_field)
@ -2358,8 +2354,6 @@ static bool reopen_table(TABLE *table)
tmp.null_row= table->null_row;
tmp.maybe_null= table->maybe_null;
tmp.status= table->status;
tmp.keys_in_use_for_query= tmp.s->keys_in_use;
tmp.used_keys= tmp.s->keys_for_keyread;
tmp.s->table_map_id= table->s->table_map_id;
@ -3820,7 +3814,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
been set for all fields (for example for view).
*/
table->used_keys.intersect(field->part_of_key);
table->covering_keys.intersect(field->part_of_key);
table->merge_keys.merge(field->part_of_key);
if (thd->mark_used_columns == MARK_COLUMNS_READ)
@ -5060,7 +5054,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
TABLE *table_1= nj_col_1->table_ref->table;
/* Mark field_1 used for table cache. */
bitmap_set_bit(table_1->read_set, field_1->field_index);
table_1->used_keys.intersect(field_1->part_of_key);
table_1->covering_keys.intersect(field_1->part_of_key);
table_1->merge_keys.merge(field_1->part_of_key);
}
if (field_2)
@ -5068,7 +5062,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
TABLE *table_2= nj_col_2->table_ref->table;
/* Mark field_2 used for table cache. */
bitmap_set_bit(table_2->read_set, field_2->field_index);
table_2->used_keys.intersect(field_2->part_of_key);
table_2->covering_keys.intersect(field_2->part_of_key);
table_2->merge_keys.merge(field_2->part_of_key);
}
@ -5704,30 +5698,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
tablenr= 0;
}
setup_table_map(table, table_list, tablenr);
table->used_keys= table->s->keys_for_keyread;
table->merge_keys.clear_all();
if (table_list->use_index)
{
key_map map;
get_key_map_from_key_list(&map, table, table_list->use_index);
if (map.is_set_all())
DBUG_RETURN(1);
/*
Don't introduce keys in keys_in_use_for_query that weren't there
before. FORCE/USE INDEX should not add keys, it should only remove
all keys except the key(s) specified in the hint.
*/
table->keys_in_use_for_query.intersect(map);
}
if (table_list->ignore_index)
{
key_map map;
get_key_map_from_key_list(&map, table, table_list->ignore_index);
if (map.is_set_all())
DBUG_RETURN(1);
table->keys_in_use_for_query.subtract(map);
}
table->used_keys.intersect(table->keys_in_use_for_query);
if (table_list->process_index_hints(table))
DBUG_RETURN(1);
}
if (tablenr > MAX_TABLES)
{
@ -6009,7 +5981,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
bitmap_set_bit(field->table->read_set, field->field_index);
if (table)
{
table->used_keys.intersect(field->part_of_key);
table->covering_keys.intersect(field->part_of_key);
table->merge_keys.merge(field->part_of_key);
}
if (tables->is_natural_join)
@ -6027,7 +5999,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (field_table)
{
thd->used_tables|= field_table->map;
field_table->used_keys.intersect(field->part_of_key);
field_table->covering_keys.intersect(field->part_of_key);
field_table->merge_keys.merge(field->part_of_key);
field_table->used_fields++;
}

View file

@ -243,6 +243,11 @@ struct system_variables
my_bool low_priority_updates;
my_bool new_mode;
/*
compatibility option:
- index usage hints (USE INDEX without a FOR clause) behave as in 5.0
*/
my_bool old_mode;
my_bool query_cache_wlock_invalidate;
my_bool engine_condition_pushdown;
my_bool innodb_table_locks;
@ -278,6 +283,7 @@ struct system_variables
DATE_TIME_FORMAT *datetime_format;
DATE_TIME_FORMAT *time_format;
my_bool sysdate_is_now;
};

View file

@ -116,7 +116,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
/* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
table->used_keys.clear_all();
table->covering_keys.clear_all();
table->quick_keys.clear_all(); // Can't use 'only index'
select=make_select(table, 0, 0, conds, 0, &error);
if (error)
@ -553,7 +553,7 @@ multi_delete::initialize_tables(JOIN *join)
tbl->no_keyread=1;
/* Don't use record cache */
tbl->no_cache= 1;
tbl->used_keys.clear_all();
tbl->covering_keys.clear_all();
if (tbl->file->has_transactions())
transactional_tables= 1;
else

View file

@ -567,7 +567,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond,
cond->fix_fields(thd, &cond); // can never fail
/* Assume that no indexes cover all required fields */
table->used_keys.clear_all();
table->covering_keys.clear_all();
SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error);
if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) ||

View file

@ -69,6 +69,17 @@ static uchar to_upper_lex[]=
208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
};
/*
Names of the index hints (for error messages). Keep in sync with
index_hint_type
*/
const char * index_hint_type_name[] =
{
"IGNORE INDEX",
"USE INDEX",
"FORCE INDEX"
};
inline int lex_casecmp(const char *s, const char *t, uint len)
{
@ -1201,7 +1212,6 @@ void st_select_lex::init_select()
group_list.empty();
type= db= 0;
having= 0;
use_index_ptr= ignore_index_ptr= 0;
table_join_options= 0;
in_sum_expr= with_wild= 0;
options= 0;
@ -1209,7 +1219,6 @@ void st_select_lex::init_select()
braces= 0;
expr_list.empty();
interval_list.empty();
use_index.empty();
ftfunc_list_alloc.empty();
inner_sum_func_list= 0;
ftfunc_list= &ftfunc_list_alloc;
@ -1436,14 +1445,11 @@ bool st_select_lex_node::inc_in_sum_expr() { return 1; }
uint st_select_lex_node::get_in_sum_expr() { return 0; }
TABLE_LIST* st_select_lex_node::get_table_list() { return 0; }
List<Item>* st_select_lex_node::get_item_list() { return 0; }
List<String>* st_select_lex_node::get_use_index() { return 0; }
List<String>* st_select_lex_node::get_ignore_index() { return 0; }
TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_join_options,
thr_lock_type flags,
List<String> *use_index,
List<String> *ignore_index,
List<index_hint> *hints,
LEX_STRING *option)
{
return 0;
@ -1550,19 +1556,6 @@ List<Item>* st_select_lex::get_item_list()
return &item_list;
}
List<String>* st_select_lex::get_use_index()
{
return use_index_ptr;
}
List<String>* st_select_lex::get_ignore_index()
{
return ignore_index_ptr;
}
ulong st_select_lex::get_table_join_options()
{
return table_join_options;
@ -2328,3 +2321,61 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
are in sql_union.cc
*/
/*
Sets the kind of hints to be added by the calls to add_index_hint().
SYNOPSIS
set_index_hint_type()
type the kind of hints to be added from now on.
clause the clause to use for hints to be added from now on.
DESCRIPTION
Used in filling up the tagged hints list.
This list is filled by first setting the kind of the hint as a
context variable and then adding hints of the current kind.
Then the context variable index_hint_type can be reset to the
next hint type.
*/
void st_select_lex::set_index_hint_type(enum index_hint_type type,
index_clause_map clause)
{
current_index_hint_type= type;
current_index_hint_clause= clause;
}
/*
Makes an array to store index usage hints (ADD/FORCE/IGNORE INDEX).
SYNOPSIS
alloc_index_hints()
thd current thread.
*/
void st_select_lex::alloc_index_hints (THD *thd)
{
index_hints= new (thd->mem_root) List<index_hint>();
}
/*
adds an element to the array storing index usage hints
(ADD/FORCE/IGNORE INDEX).
SYNOPSIS
add_index_hint()
thd current thread.
str name of the index.
length number of characters in str.
RETURN VALUE
0 on success, non-zero otherwise
*/
bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
{
return index_hints->push_front (new (thd->mem_root)
index_hint(current_index_hint_type,
current_index_hint_clause,
str, length));
}

View file

@ -216,6 +216,47 @@ enum tablespace_op_type
NO_TABLESPACE_OP, DISCARD_TABLESPACE, IMPORT_TABLESPACE
};
/*
String names used to print a statement with index hints.
Keep in sync with index_hint_type.
*/
extern const char * index_hint_type_name[];
typedef byte index_clause_map;
/*
Bits in index_clause_map : one for each possible FOR clause in
USE/FORCE/IGNORE INDEX index hint specification
*/
#define INDEX_HINT_MASK_JOIN (1)
#define INDEX_HINT_MASK_GROUP (1 << 1)
#define INDEX_HINT_MASK_ORDER (1 << 2)
#define INDEX_HINT_MASK_ALL (INDEX_HINT_MASK_JOIN | INDEX_HINT_MASK_GROUP | \
INDEX_HINT_MASK_ORDER)
/* Single element of an USE/FORCE/IGNORE INDEX list specified as a SQL hint */
class index_hint : public Sql_alloc
{
public:
/* The type of the hint : USE/FORCE/IGNORE */
enum index_hint_type type;
/* Where the hit applies to. A bitmask of INDEX_HINT_MASK_<place> values */
index_clause_map clause;
/*
The index name. Empty (str=NULL) name represents an empty list
USE INDEX () clause
*/
LEX_STRING key_name;
index_hint (enum index_hint_type type_arg, index_clause_map clause_arg,
char *str, uint length) :
type(type_arg), clause(clause_arg)
{
key_name.str= str;
key_name.length= length;
}
};
/*
The state of the lex parsing for selects
@ -394,15 +435,12 @@ public:
virtual uint get_in_sum_expr();
virtual TABLE_LIST* get_table_list();
virtual List<Item>* get_item_list();
virtual List<String>* get_use_index();
virtual List<String>* get_ignore_index();
virtual ulong get_table_join_options();
virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0,
List<index_hint> *hints= 0,
LEX_STRING *option= 0);
virtual void set_lock_for_tables(thr_lock_type lock_type) {}
@ -532,8 +570,7 @@ public:
SQL_LIST table_list;
SQL_LIST group_list; /* GROUP BY clause. */
List<Item> item_list; /* list of fields & expressions */
List<String> interval_list, use_index, *use_index_ptr,
ignore_index, *ignore_index_ptr;
List<String> interval_list;
bool is_item_list_lookup;
/*
Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake
@ -680,8 +717,7 @@ public:
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0,
List<index_hint> *hints= 0,
LEX_STRING *option= 0);
TABLE_LIST* get_table_list();
bool init_nested_join(THD *thd);
@ -690,8 +726,6 @@ public:
void add_joined_table(TABLE_LIST *table);
TABLE_LIST *convert_right_join();
List<Item>* get_item_list();
List<String>* get_use_index();
List<String>* get_ignore_index();
ulong get_table_join_options();
void set_lock_for_tables(thr_lock_type lock_type);
inline void init_order()
@ -731,6 +765,33 @@ public:
select lexes.
*/
void cleanup_all_joins(bool full);
void set_index_hint_type(enum index_hint_type type, index_clause_map clause);
/*
Add a index hint to the tagged list of hints. The type and clause of the
hint will be the current ones (set by set_index_hint())
*/
bool add_index_hint (THD *thd, char *str, uint length);
/* make a list to hold index hints */
void alloc_index_hints (THD *thd);
/* read and clear the index hints */
List<index_hint>* pop_index_hints(void)
{
List<index_hint> *hints= index_hints;
index_hints= NULL;
return hints;
}
void clear_index_hints(void) { index_hints= NULL; }
private:
/* current index hint kind. used in filling up index_hints */
enum index_hint_type current_index_hint_type;
index_clause_map current_index_hint_clause;
/* a list of USE/FORCE/IGNORE INDEX */
List<index_hint> *index_hints;
};
typedef class st_select_lex SELECT_LEX;

View file

@ -1417,8 +1417,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
/* 'parent_lex' is used in init_query() so it must be before it. */
sel->parent_lex= lex;
sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
(List<String> *) 0, (List<String> *) 0))
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
DBUG_RETURN(1);
lex->query_tables_last= query_tables_last;
TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
@ -4708,7 +4707,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
uint found=0;
ulong found_access=0;
#ifndef EMBEDDED_LIBRARY
#ifndef NO_EMBEDDED_ACCESS_CHECKS
TABLE_LIST *org_tables= tables;
#endif
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
@ -5461,8 +5460,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_STRING *alias,
ulong table_options,
thr_lock_type lock_type,
List<String> *use_index_arg,
List<String> *ignore_index_arg,
List<index_hint> *index_hints_arg,
LEX_STRING *option)
{
register TABLE_LIST *ptr;
@ -5537,12 +5535,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1;
if (use_index_arg)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
sizeof(*use_index_arg));
if (ignore_index_arg)
ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index_arg,
sizeof(*ignore_index_arg));
ptr->index_hints= index_hints_arg;
ptr->option= option ? option->str : 0;
/* check that used name is unique */
if (lock_type != TL_IGNORE)

View file

@ -163,13 +163,15 @@ static COND *make_cond_for_table(COND *cond,table_map table,
static Item* part_of_refkey(TABLE *form,Field *field);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
ha_rows select_limit, bool no_changes,
key_map *map);
static bool list_contains_unique_index(TABLE *table,
bool (*find_func) (Field *, void *), void *data);
static bool find_field_in_item_list (Field *field, void *data);
static bool find_field_in_order_list (Field *field, void *data);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit);
ha_rows filesort_limit, ha_rows select_limit,
bool is_order_by);
static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
Item *having);
static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
@ -652,7 +654,7 @@ void JOIN::remove_subq_pushed_predicates(Item **where)
static void save_index_subquery_explain_info(JOIN_TAB *join_tab, Item* where)
{
join_tab->packed_info= TAB_INFO_HAVE_VALUE;
if (join_tab->table->used_keys.is_set(join_tab->ref.key))
if (join_tab->table->covering_keys.is_set(join_tab->ref.key))
join_tab->packed_info |= TAB_INFO_USING_INDEX;
if (where)
join_tab->packed_info |= TAB_INFO_USING_WHERE;
@ -1024,14 +1026,15 @@ JOIN::optimize()
JOIN_TAB *tab= &join_tab[const_tables];
bool all_order_fields_used;
if (order)
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1,
&tab->table->keys_in_use_for_order_by);
if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
order, fields_list,
&all_order_fields_used)))
{
bool skip_group= (skip_sort_order &&
test_if_skip_sort_order(tab, group_list, select_limit,
1) != 0);
test_if_skip_sort_order(tab, group_list, select_limit, 1,
&tab->table->keys_in_use_for_group_by) != 0);
if ((skip_group && all_order_fields_used) ||
select_limit == HA_POS_ERROR ||
(order && !skip_sort_order))
@ -1229,7 +1232,9 @@ JOIN::optimize()
((group_list &&
(!simple_group ||
!test_if_skip_sort_order(&join_tab[const_tables], group_list,
unit->select_limit_cnt, 0))) ||
unit->select_limit_cnt, 0,
&join_tab[const_tables].table->
keys_in_use_for_group_by))) ||
select_distinct) &&
tmp_table_param.quick_group && !procedure)
{
@ -1331,7 +1336,7 @@ JOIN::optimize()
DBUG_PRINT("info",("Sorting for group"));
thd->proc_info="Sorting for group";
if (create_sort_index(thd, this, group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1) ||
setup_sum_funcs(thd, sum_funcs))
@ -1348,7 +1353,7 @@ JOIN::optimize()
DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order";
if (create_sort_index(thd, this, order,
HA_POS_ERROR, HA_POS_ERROR))
HA_POS_ERROR, HA_POS_ERROR, TRUE))
DBUG_RETURN(1);
order=0;
}
@ -1375,7 +1380,9 @@ JOIN::optimize()
{
/* Should always succeed */
if (test_if_skip_sort_order(&join_tab[const_tables],
order, unit->select_limit_cnt, 0))
order, unit->select_limit_cnt, 0,
&join_tab[const_tables].table->
keys_in_use_for_order_by))
order=0;
}
}
@ -1568,7 +1575,9 @@ JOIN::exec()
(const_tables == tables ||
((simple_order || skip_sort_order) &&
test_if_skip_sort_order(&join_tab[const_tables], order,
select_limit, 0))))
select_limit, 0,
&join_tab[const_tables].table->
keys_in_use_for_order_by))))
order=0;
having= tmp_having;
select_describe(this, need_tmp,
@ -1744,7 +1753,7 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
if (create_sort_index(thd, curr_join, curr_join->group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
make_group_fields(this, curr_join))
{
DBUG_VOID_RETURN;
@ -1960,7 +1969,8 @@ JOIN::exec()
curr_join->group_list : curr_join->order,
curr_join->select_limit,
(select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR : unit->select_limit_cnt)))
HA_POS_ERROR : unit->select_limit_cnt),
curr_join->group_list ? TRUE : FALSE))
DBUG_VOID_RETURN;
sortorder= curr_join->sortorder;
if (curr_join->const_tables != curr_join->tables &&
@ -3964,7 +3974,7 @@ best_access_path(JOIN *join,
/* Limit the number of matched rows */
tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys.is_set(key))
if (table->covering_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->stats.block_size/2/
@ -4131,7 +4141,7 @@ best_access_path(JOIN *join,
/* Limit the number of matched rows */
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys.is_set(key))
if (table->covering_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->stats.block_size/2/
@ -4190,7 +4200,7 @@ best_access_path(JOIN *join,
!(s->quick && best_key && s->quick->index == best_key->key && // (2)
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2)
!((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3)
! s->table->used_keys.is_clear_all() && best_key) && // (3)
! s->table->covering_keys.is_clear_all() && best_key) && // (3)
!(s->table->force_index && best_key && !s->quick)) // (4)
{ // Check full join
ha_rows rnd_records= s->found_records;
@ -6096,10 +6106,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
*/
if (!ordered_set &&
(table == join->sort_by_table &&
(!join->order || join->skip_sort_order ||
test_if_skip_sort_order(tab, join->order, join->select_limit,
1))
) ||
(!join->order || join->skip_sort_order)) ||
(join->sort_by_table == (TABLE *) 1 && i != join->const_tables))
ordered_set= 1;
@ -6115,7 +6122,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
table->status=STATUS_NO_RECORD;
tab->read_first_record= join_read_const;
tab->read_record.read_record= join_no_more_records;
if (table->used_keys.is_set(tab->ref.key) &&
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -6133,7 +6140,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
tab->quick=0;
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
if (table->used_keys.is_set(tab->ref.key) &&
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -6150,7 +6157,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
}
delete tab->quick;
tab->quick=0;
if (table->used_keys.is_set(tab->ref.key) &&
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -6236,15 +6243,15 @@ make_join_readinfo(JOIN *join, ulonglong options)
{
if (tab->select && tab->select->quick &&
tab->select->quick->index != MAX_KEY && //not index_merge
table->used_keys.is_set(tab->select->quick->index))
table->covering_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
else if (!table->used_keys.is_clear_all() &&
else if (!table->covering_keys.is_clear_all() &&
!(tab->select && tab->select->quick))
{ // Only read index tree
tab->index=find_shortest_key(table, & table->used_keys);
tab->index=find_shortest_key(table, & table->covering_keys);
tab->read_first_record= join_read_first;
tab->type=JT_NEXT; // Read with index_first / index_next
}
@ -9378,7 +9385,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->copy_blobs= 1;
table->in_use= thd;
table->quick_keys.init();
table->used_keys.init();
table->covering_keys.init();
table->keys_in_use_for_query.init();
table->s= share;
@ -11003,7 +11010,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
}
else
{
if (!table->key_read && table->used_keys.is_set(tab->ref.key) &&
if (!table->key_read && table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread &&
(int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY)
{
@ -11310,7 +11317,7 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
if (!table->key_read && table->used_keys.is_set(tab->index) &&
if (!table->key_read && table->covering_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -11349,7 +11356,7 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
if (!table->key_read && table->used_keys.is_set(tab->index) &&
if (!table->key_read && table->covering_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -12373,7 +12380,7 @@ find_field_in_item_list (Field *field, void *data)
static bool
test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
bool no_changes)
bool no_changes, key_map *map)
{
int ref_key;
uint ref_key_parts;
@ -12383,14 +12390,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
DBUG_ENTER("test_if_skip_sort_order");
LINT_INIT(ref_key_parts);
/* Check which keys can be used to resolve ORDER BY. */
usable_keys= table->keys_in_use_for_query;
/*
Keys disabled by ALTER TABLE ... DISABLE KEYS should have already
been taken into account.
*/
DBUG_ASSERT(usable_keys.is_subset(table->s->keys_in_use));
usable_keys= *map;
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
@ -12448,8 +12452,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If using index only read, only consider other possible index only
keys
*/
if (table->used_keys.is_set(ref_key))
usable_keys.intersect(table->used_keys);
if (table->covering_keys.is_set(ref_key))
usable_keys.intersect(table->covering_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
&usable_keys)) < MAX_KEY)
{
@ -12564,7 +12568,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if (select_limit >= table->file->stats.records)
{
keys= *table->file->keys_to_use_for_scanning();
keys.merge(table->used_keys);
keys.merge(table->covering_keys);
/*
We are adding here also the index specified in FORCE INDEX clause,
@ -12592,7 +12596,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
tab->read_first_record= (flag > 0 ? join_read_first:
join_read_last);
tab->type=JT_NEXT; // Read with index_first(), index_next()
if (table->used_keys.is_set(nr))
if (table->covering_keys.is_set(nr))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@ -12618,6 +12622,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
filesort_limit Max number of rows that needs to be sorted
select_limit Max number of rows in final output
Used to decide if we should use index or not
is_order_by true if we are sorting on ORDER BY, false if GROUP BY
Used to decide if we should use index or not
IMPLEMENTATION
@ -12636,7 +12642,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
static int
create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit)
ha_rows filesort_limit, ha_rows select_limit,
bool is_order_by)
{
uint length= 0;
ha_rows examined_rows;
@ -12657,7 +12664,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
*/
if ((order != join->group_list ||
!(join->select_options & SELECT_BIG_RESULT)) &&
test_if_skip_sort_order(tab,order,select_limit,0))
test_if_skip_sort_order(tab,order,select_limit,0,
is_order_by ? &table->keys_in_use_for_order_by :
&table->keys_in_use_for_group_by))
DBUG_RETURN(0);
for (ORDER *ord= join->order; ord; ord= ord->next)
length++;
@ -15285,7 +15294,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
/* Build "Extra" field and add it to item_list. */
my_bool key_read=table->key_read;
if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
table->used_keys.is_set(tab->index))
table->covering_keys.is_set(tab->index))
key_read=1;
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
!((QUICK_ROR_INTERSECT_SELECT*)tab->select->quick)->need_to_fetch_row)

View file

@ -1221,7 +1221,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (key_part->field &&
(key_part->length !=
table->field[key_part->fieldnr-1]->key_length() &&
!(key_info->flags & HA_FULLTEXT)))
!(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
{
char *end;
buff[0] = '(';
@ -2266,8 +2266,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel,
ident_table.length= strlen(table);
table_ident= new Table_ident(thd, ident_db, ident_table, 1);
sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
(List<String> *) 0, (List<String> *) 0))
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
return 1;
return 0;
}
@ -5033,8 +5032,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
strlen(schema_table->table_name), 0);
if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
0, 0, TL_READ, (List<String> *) 0,
(List<String> *) 0))
0, 0, TL_READ))
{
DBUG_RETURN(1);
}

View file

@ -2791,6 +2791,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
column->length*= sql_field->charset->mbmaxlen;
if (key->type == Key::SPATIAL && column->length)
{
my_error(ER_WRONG_SUB_KEY, MYF(0));
DBUG_RETURN(-1);
}
if (f_is_blob(sql_field->pack_flag) ||
(f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
{
@ -2884,6 +2890,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
else if (!f_is_geom(sql_field->pack_flag) &&
(column->length > length ||
!Field::type_can_have_key_part (sql_field->sql_type) ||
((f_is_packed(sql_field->pack_flag) ||
((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
(key_info->flags & HA_NOSAME))) &&
@ -5859,6 +5866,8 @@ view_err:
*/
if (!Field::type_can_have_key_part(cfield->field->type()) ||
!Field::type_can_have_key_part(cfield->sql_type) ||
/* spatial keys can't have sub-key length */
(key_info->flags & HA_SPATIAL) ||
(cfield->field->field_length == key_part_length &&
!f_is_blob(key_part->key_type)) ||
(cfield->length && (cfield->length < key_part_length /

View file

@ -126,7 +126,7 @@ int mysql_update(THD *thd,
#endif
uint table_count= 0;
ha_rows updated, found;
key_map old_used_keys;
key_map old_covering_keys;
TABLE *table;
SQL_SELECT *select;
READ_RECORD info;
@ -165,8 +165,8 @@ int mysql_update(THD *thd,
thd->proc_info="init";
table= table_list->table;
/* Calculate "table->used_keys" based on the WHERE */
table->used_keys= table->s->keys_in_use;
/* Calculate "table->covering_keys" based on the WHERE */
table->covering_keys= table->s->keys_in_use;
table->quick_keys.clear_all();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@ -176,7 +176,7 @@ int mysql_update(THD *thd,
if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
DBUG_RETURN(1);
old_used_keys= table->used_keys; // Keys used in WHERE
old_covering_keys= table->covering_keys; // Keys used in WHERE
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
@ -229,7 +229,7 @@ int mysql_update(THD *thd,
limit= 0; // Impossible WHERE
}
// Don't count on usage of 'only index' when calculating which key to use
table->used_keys.clear_all();
table->covering_keys.clear_all();
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (prune_partitions(thd, table, conds))
@ -304,7 +304,7 @@ int mysql_update(THD *thd,
We can't update table directly; We must first search after all
matching rows before updating the table!
*/
if (used_index < MAX_KEY && old_used_keys.is_set(used_index))
if (used_index < MAX_KEY && old_covering_keys.is_set(used_index))
{
table->key_read=1;
table->mark_columns_used_by_index(used_index);
@ -1092,7 +1092,7 @@ int multi_update::prepare(List<Item> &not_used_values,
}
/*
We have to check values after setup_tables to get used_keys right in
We have to check values after setup_tables to get covering_keys right in
reference tables
*/
@ -1119,7 +1119,7 @@ int multi_update::prepare(List<Item> &not_used_values,
update.link_in_list((byte*) tl, (byte**) &tl->next_local);
tl->shared= table_count++;
table->no_keyread=1;
table->used_keys.clear_all();
table->covering_keys.clear_all();
table->pos_in_table_list= tl;
}
}

View file

@ -481,6 +481,7 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
struct st_lex *lex;
sp_head *sphead;
struct p_elem_val *p_elem_value;
enum index_hint_type index_hint;
}
%{
@ -1162,7 +1163,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
btree_or_rtree
%type <string_list>
key_usage_list using_list
using_list
%type <key_part>
key_part
@ -1233,7 +1234,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_column_list grant_privileges grant_ident grant_list grant_option
object_privilege object_privilege_list user_list rename_list
clear_privileges flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
equal optional_braces
opt_mi_check_type opt_to mi_check_types normal_join
db_to_db table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
@ -1269,6 +1270,8 @@ END_OF_INPUT
%type <spblock> sp_decls sp_decl
%type <lex> sp_cursor_stmt
%type <spname> sp_name
%type <index_hint> index_hint_type
%type <num> index_hint_clause
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
@ -5940,12 +5943,8 @@ keycache_list:
assign_to_keycache:
table_ident cache_keys_spec
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
if (!sel->add_table_to_list(lex->thd, $1, NULL, 0,
TL_READ,
sel->get_use_index(),
(List<String> *)0))
if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
;
@ -5972,33 +5971,26 @@ preload_list:
preload_keys:
table_ident cache_keys_spec opt_ignore_leaves
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
if (!sel->add_table_to_list(lex->thd, $1, NULL, $3,
TL_READ,
sel->get_use_index(),
(List<String> *)0))
if (!Select->add_table_to_list(YYTHD, $1, NULL, $3, TL_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
;
cache_keys_spec:
{ Select->interval_list.empty(); }
cache_key_list_or_empty
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
sel->use_index= sel->interval_list;
{
Lex->select_lex.alloc_index_hints(YYTHD);
Select->set_index_hint_type(INDEX_HINT_USE,
global_system_variables.old_mode ?
INDEX_HINT_MASK_JOIN :
INDEX_HINT_MASK_ALL);
}
cache_key_list_or_empty
;
cache_key_list_or_empty:
/* empty */ { Lex->select_lex.use_index_ptr= 0; }
| opt_key_or_index '(' key_usage_list2 ')'
{
SELECT_LEX *sel= &Lex->select_lex;
sel->use_index_ptr= &sel->use_index;
}
/* empty */ { }
| key_or_index '(' opt_key_usage_list ')'
;
opt_ignore_leaves:
@ -7371,20 +7363,16 @@ normal_join:
table_factor:
{
SELECT_LEX *sel= Select;
sel->use_index_ptr=sel->ignore_index_ptr=0;
sel->table_join_options= 0;
}
table_ident opt_table_alias opt_key_definition
{
LEX *lex= Lex;
SELECT_LEX *sel= lex->current_select;
if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
sel->get_table_join_options(),
lex->lock_option,
sel->get_use_index(),
sel->get_ignore_index())))
if (!($$= Select->add_table_to_list(YYTHD, $2, $3,
Select->get_table_join_options(),
Lex->lock_option,
Select->pop_index_hints())))
MYSQL_YYABORT;
sel->add_joined_table($$);
Select->add_joined_table($$);
}
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref
ON
@ -7453,8 +7441,7 @@ table_factor:
lex->current_select= sel= unit->outer_select();
if (!($$= sel->
add_table_to_list(lex->thd, new Table_ident(unit), $6, 0,
TL_READ,(List<String> *)0,
(List<String> *)0)))
TL_READ)))
MYSQL_YYABORT;
sel->add_joined_table($$);
@ -7553,52 +7540,67 @@ opt_outer:
/* empty */ {}
| OUTER {};
index_hint_clause:
/* empty */
{
$$= global_system_variables.old_mode ?
INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL;
}
| FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; }
| FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; }
| FOR_SYM GROUP_SYM BY { $$= INDEX_HINT_MASK_GROUP; }
;
index_hint_type:
FORCE_SYM { $$= INDEX_HINT_FORCE; }
| IGNORE_SYM { $$= INDEX_HINT_IGNORE; }
;
index_hint_definition:
index_hint_type key_or_index index_hint_clause
{
Select->set_index_hint_type($1, $3);
}
'(' key_usage_list ')';
| USE_SYM key_or_index index_hint_clause
{
Select->set_index_hint_type(INDEX_HINT_USE, $3);
}
'(' opt_key_usage_list ')';
index_hints_list:
index_hint_definition
| index_hints_list index_hint_definition
;
opt_index_hints_list:
/* empty */
| { Select->alloc_index_hints(YYTHD); } index_hints_list
;
opt_key_definition:
/* empty */ {}
| USE_SYM key_usage_list
{
SELECT_LEX *sel= Select;
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
}
| FORCE_SYM key_usage_list
{
SELECT_LEX *sel= Select;
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
sel->table_join_options|= TL_OPTION_FORCE_INDEX;
}
| IGNORE_SYM key_usage_list
{
SELECT_LEX *sel= Select;
sel->ignore_index= *$2;
sel->ignore_index_ptr= &sel->ignore_index;
};
{ Select->clear_index_hints(); }
opt_index_hints_list
;
opt_key_usage_list:
/* empty */ { Select->add_index_hint(YYTHD, NULL, 0); }
| key_usage_list {}
;
key_usage_element:
ident { Select->add_index_hint(YYTHD, $1.str, $1.length); }
| PRIMARY_SYM
{
Select->add_index_hint(YYTHD, (char *)"PRIMARY", 7);
}
;
key_usage_list:
key_or_index { Select->interval_list.empty(); }
'(' key_list_or_empty ')'
{ $$= &Select->interval_list; }
;
key_list_or_empty:
/* empty */ {}
| key_usage_list2 {}
;
key_usage_list2:
key_usage_list2 ',' ident
{ Select->
interval_list.push_back(new (YYTHD->mem_root) String((const char*) $3.str, $3.length,
system_charset_info)); }
| ident
{ Select->
interval_list.push_back(new (YYTHD->mem_root) String((const char*) $1.str, $1.length,
system_charset_info)); }
| PRIMARY_SYM
{ Select->
interval_list.push_back(new (YYTHD->mem_root) String("PRIMARY", 7,
system_charset_info)); };
key_usage_element
| key_usage_list ',' key_usage_element
;
using_list:
ident

View file

@ -1338,7 +1338,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
if (!(outparam->alias= my_strdup(alias, MYF(MY_WME))))
goto err;
outparam->quick_keys.init();
outparam->used_keys.init();
outparam->covering_keys.init();
outparam->keys_in_use_for_query.init();
/* Allocate handler */
@ -4120,6 +4120,175 @@ Item_subselect *st_table_list::containing_subselect()
return (select_lex ? select_lex->master_unit()->item : 0);
}
/*
Compiles the tagged hints list and fills up the bitmasks.
SYNOPSIS
process_index_hints()
table the TABLE to operate on.
DESCRIPTION
The parser collects the index hints for each table in a "tagged list"
(st_table_list::index_hints). Using the information in this tagged list
this function sets the members st_table::keys_in_use_for_query,
st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
st_table::force_index and st_table::covering_keys.
Current implementation of the runtime does not allow mixing FORCE INDEX
and USE INDEX, so this is checked here. Then the FORCE INDEX list
(if non-empty) is appended to the USE INDEX list and a flag is set.
Multiple hints of the same kind are processed so that each clause
is applied to what is computed in the previous clause.
For example:
USE INDEX (i1) USE INDEX (i2)
is equivalent to
USE INDEX (i1,i2)
and means "consider only i1 and i2".
Similarly
USE INDEX () USE INDEX (i1)
is equivalent to
USE INDEX (i1)
and means "consider only the index i1"
It is OK to have the same index several times, e.g. "USE INDEX (i1,i1)" is
not an error.
Different kind of hints (USE/FORCE/IGNORE) are processed in the following
order:
1. All indexes in USE (or FORCE) INDEX are added to the mask.
2. All IGNORE INDEX
e.g. "USE INDEX i1, IGNORE INDEX i1, USE INDEX i1" will not use i1 at all
as if we had "USE INDEX i1, USE INDEX i1, IGNORE INDEX i1".
As an optimization if there is a covering index, and we have
IGNORE INDEX FOR GROUP/ORDER, and this index is used for the JOIN part,
then we have to ignore the IGNORE INDEX FROM GROUP/ORDER.
RETURN VALUE
FALSE no errors found
TRUE found and reported an error.
*/
bool st_table_list::process_index_hints(TABLE *table)
{
/* initialize the result variables */
table->keys_in_use_for_query= table->keys_in_use_for_group_by=
table->keys_in_use_for_order_by= table->s->keys_in_use;
/* index hint list processing */
if (index_hints)
{
key_map index_join[INDEX_HINT_FORCE + 1];
key_map index_order[INDEX_HINT_FORCE + 1];
key_map index_group[INDEX_HINT_FORCE + 1];
index_hint *hint;
int type;
bool have_empty_use_join= FALSE, have_empty_use_order= FALSE,
have_empty_use_group= FALSE;
List_iterator <index_hint> iter(*index_hints);
/* initialize temporary variables used to collect hints of each kind */
for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
{
index_join[type].clear_all();
index_order[type].clear_all();
index_group[type].clear_all();
}
/* iterate over the hints list */
while ((hint= iter++))
{
uint pos;
/* process empty USE INDEX () */
if (hint->type == INDEX_HINT_USE && !hint->key_name.str)
{
if (hint->clause & INDEX_HINT_MASK_JOIN)
{
index_join[hint->type].clear_all();
have_empty_use_join= TRUE;
}
if (hint->clause & INDEX_HINT_MASK_ORDER)
{
index_order[hint->type].clear_all();
have_empty_use_order= TRUE;
}
if (hint->clause & INDEX_HINT_MASK_GROUP)
{
index_group[hint->type].clear_all();
have_empty_use_group= TRUE;
}
continue;
}
/*
Check if an index with the given name exists and get his offset in
the keys bitmask for the table
*/
if (table->s->keynames.type_names == 0 ||
(pos= find_type(&table->s->keynames, hint->key_name.str,
hint->key_name.length, 1)) <= 0)
{
my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias);
return 1;
}
pos--;
/* add to the appropriate clause mask */
if (hint->clause & INDEX_HINT_MASK_JOIN)
index_join[hint->type].set_bit (pos);
if (hint->clause & INDEX_HINT_MASK_ORDER)
index_order[hint->type].set_bit (pos);
if (hint->clause & INDEX_HINT_MASK_GROUP)
index_group[hint->type].set_bit (pos);
}
/* cannot mix USE INDEX and FORCE INDEX */
if ((!index_join[INDEX_HINT_FORCE].is_clear_all() ||
!index_order[INDEX_HINT_FORCE].is_clear_all() ||
!index_group[INDEX_HINT_FORCE].is_clear_all()) &&
(!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join ||
!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order ||
!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group))
{
my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE],
index_hint_type_name[INDEX_HINT_FORCE]);
return 1;
}
/* process FORCE INDEX as USE INDEX with a flag */
if (!index_join[INDEX_HINT_FORCE].is_clear_all() ||
!index_order[INDEX_HINT_FORCE].is_clear_all() ||
!index_group[INDEX_HINT_FORCE].is_clear_all())
{
table->force_index= TRUE;
index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]);
index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]);
index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]);
}
/* apply USE INDEX */
if (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join)
table->keys_in_use_for_query.intersect(index_join[INDEX_HINT_USE]);
if (!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order)
table->keys_in_use_for_order_by.intersect (index_order[INDEX_HINT_USE]);
if (!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group)
table->keys_in_use_for_group_by.intersect (index_group[INDEX_HINT_USE]);
/* apply IGNORE INDEX */
table->keys_in_use_for_query.subtract (index_join[INDEX_HINT_IGNORE]);
table->keys_in_use_for_order_by.subtract (index_order[INDEX_HINT_IGNORE]);
table->keys_in_use_for_group_by.subtract (index_group[INDEX_HINT_IGNORE]);
}
/* make sure covering_keys don't include indexes disabled with a hint */
table->covering_keys.intersect(table->keys_in_use_for_query);
return 0;
}
/*****************************************************************************
** Instansiate templates
*****************************************************************************/

View file

@ -299,6 +299,12 @@ typedef struct st_table_share
/* Information for one open table */
enum index_hint_type
{
INDEX_HINT_IGNORE,
INDEX_HINT_USE,
INDEX_HINT_FORCE
};
struct st_table {
st_table() {} /* Remove gcc warning */
@ -318,8 +324,12 @@ struct st_table {
byte *write_row_record; /* Used as optimisation in
THD::write_row */
byte *insert_values; /* used by INSERT ... UPDATE */
key_map quick_keys, used_keys;
/*
Map of keys that can be used to retrieve all data from this table
needed by the query without reading the row.
*/
key_map covering_keys;
key_map quick_keys, merge_keys;
/*
A set of keys that can be used in the query that references this
table.
@ -332,7 +342,10 @@ struct st_table {
The set is implemented as a bitmap.
*/
key_map keys_in_use_for_query;
key_map merge_keys;
/* Map of keys that can be used to calculate GROUP BY without sorting */
key_map keys_in_use_for_group_by;
/* Map of keys that can be used to calculate ORDER BY without sorting */
key_map keys_in_use_for_order_by;
KEY *key_info; /* data of keys in database */
Field *next_number_field; /* Set if next_number is activated */
@ -666,6 +679,7 @@ public:
(TABLE_LIST::join_using_fields != NULL)
*/
class index_hint;
typedef struct st_table_list
{
st_table_list() {} /* Remove gcc warning */
@ -722,7 +736,7 @@ typedef struct st_table_list
*/
struct st_table_list *next_name_resolution_table;
/* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */
List<String> *use_index, *ignore_index;
List<index_hint> *index_hints;
TABLE *table; /* opened table */
uint table_id; /* table id (from binlog) for opened table */
/*
@ -896,6 +910,13 @@ typedef struct st_table_list
void reinit_before_use(THD *thd);
Item_subselect *containing_subselect();
/*
Compiles the tagged hints list and fills up st_table::keys_in_use_for_query,
st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
st_table::force_index and st_table::covering_keys.
*/
bool process_index_hints(TABLE *table);
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);

View file

@ -1156,23 +1156,22 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
KEY_CACHE *new_key_cache= check_opt->key_cache;
const char *errmsg= 0;
int error= HA_ADMIN_OK;
ulonglong map= ~(ulonglong) 0;
ulonglong map;
TABLE_LIST *table_list= table->pos_in_table_list;
DBUG_ENTER("ha_myisam::assign_to_keycache");
/* Check validity of the index references */
if (table_list->use_index)
table->keys_in_use_for_query.clear_all();
if (table_list->process_index_hints(table))
{
/* We only come here when the user did specify an index map */
key_map kmap;
if (get_key_map_from_key_list(&kmap, table, table_list->use_index))
{
errmsg= thd->net.last_error;
error= HA_ADMIN_FAILED;
goto err;
}
map= kmap.to_ulonglong();
errmsg= thd->net.last_error;
error= HA_ADMIN_FAILED;
goto err;
}
map= ~(ulonglong) 0;
if (!table->keys_in_use_for_query.is_clear_all())
/* use all keys if there's no list specified by the user through hints */
map= table->keys_in_use_for_query.to_ulonglong();
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
{
@ -1208,27 +1207,27 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
{
int error;
const char *errmsg;
ulonglong map= ~(ulonglong) 0;
ulonglong map;
TABLE_LIST *table_list= table->pos_in_table_list;
my_bool ignore_leaves= table_list->ignore_leaves;
DBUG_ENTER("ha_myisam::preload_keys");
/* Check validity of the index references */
if (table_list->use_index)
table->keys_in_use_for_query.clear_all();
if (table_list->process_index_hints(table))
{
key_map kmap;
get_key_map_from_key_list(&kmap, table, table_list->use_index);
if (kmap.is_set_all())
{
errmsg= thd->net.last_error;
error= HA_ADMIN_FAILED;
goto err;
}
if (!kmap.is_clear_all())
map= kmap.to_ulonglong();
errmsg= thd->net.last_error;
error= HA_ADMIN_FAILED;
goto err;
}
map= ~(ulonglong) 0;
/* Check validity of the index references */
if (!table->keys_in_use_for_query.is_clear_all())
/* use all keys if there's no list specified by the user through hints */
map= table->keys_in_use_for_query.to_ulonglong();
mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
(void *) &thd->variables.preload_buff_size);