Skip to content

Commit f735822

Browse files
committed
Fixed bug mdev-5721.
Do not define a look-up key for a temporary table if its length exceeds the maximum length of such keys.
1 parent 8dae5a8 commit f735822

File tree

6 files changed

+277
-6
lines changed

6 files changed

+277
-6
lines changed

include/myisam.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ extern "C" {
4848
#endif
4949

5050
#define MI_MAX_POSSIBLE_KEY_BUFF HA_MAX_POSSIBLE_KEY_BUFF
51+
/*
52+
The following defines can be increased if necessary.
53+
But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and MI_MAX_KEY_LENGTH.
54+
*/
55+
#define MI_MAX_KEY_LENGTH 1000 /* Max length in bytes */
56+
#define MI_MAX_KEY_SEG 16 /* Max segments for key */
5157

5258
#define MI_NAME_IEXT ".MYI"
5359
#define MI_NAME_DEXT ".MYD"

mysql-test/r/derived_view.result

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2396,6 +2396,94 @@ deallocate prepare stmt;
23962396
drop table t1,t2;
23972397
set optimizer_switch=@save_optimizer_switch5740;
23982398
#
2399+
# Bug mdev-5721: possible long key access to a materialized derived table
2400+
# (see also the test case for Bug#13261277 that is actually the same bug)
2401+
#
2402+
CREATE TABLE t1 (
2403+
id varchar(255) NOT NULL DEFAULT '',
2404+
familyid int(11) DEFAULT NULL,
2405+
withdrawndate date DEFAULT NULL,
2406+
KEY index_td_familyid_id (familyid,id)
2407+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
2408+
CREATE TABLE t2 (
2409+
id int(11) NOT NULL AUTO_INCREMENT,
2410+
activefromts datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
2411+
shortdescription text,
2412+
useraccessfamily varchar(512) DEFAULT NULL,
2413+
serialized longtext,
2414+
PRIMARY KEY (id)
2415+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
2416+
insert into t1 values ('picture/89/1369722032695.pmd',89,NULL);
2417+
insert into t1 values ('picture/90/1369832057370.pmd',90,NULL);
2418+
insert into t2 values (38,'2013-03-04 07:49:22','desc','CODE','string');
2419+
EXPLAIN
2420+
SELECT * FROM t2 x,
2421+
(SELECT t2.useraccessfamily, t2.serialized AS picturesubuser, COUNT(*)
2422+
FROM t2, t1 GROUP BY t2.useraccessfamily, picturesubuser) y
2423+
WHERE x.useraccessfamily = y.useraccessfamily;
2424+
id select_type table type possible_keys key key_len ref rows Extra
2425+
1 PRIMARY x system NULL NULL NULL NULL 1
2426+
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 Using where
2427+
2 DERIVED t2 system NULL NULL NULL NULL 1
2428+
2 DERIVED t1 index NULL index_td_familyid_id 772 NULL 2 Using index
2429+
SELECT * FROM t2 x,
2430+
(SELECT t2.useraccessfamily, t2.serialized AS picturesubuser, COUNT(*)
2431+
FROM t2, t1 GROUP BY t2.useraccessfamily, picturesubuser) y
2432+
WHERE x.useraccessfamily = y.useraccessfamily;
2433+
id activefromts shortdescription useraccessfamily serialized useraccessfamily picturesubuser COUNT(*)
2434+
38 2013-03-04 07:49:22 desc CODE string CODE string 2
2435+
DROP TABLE t1,t2;
2436+
#
2437+
# Bug#13261277: Unchecked key length caused missing records.
2438+
#
2439+
CREATE TABLE t1 (
2440+
col_varchar varchar(1024) CHARACTER SET utf8 DEFAULT NULL,
2441+
stub1 varchar(1024) CHARACTER SET utf8 DEFAULT NULL,
2442+
stub2 varchar(1024) CHARACTER SET utf8 DEFAULT NULL,
2443+
stub3 varchar(1024) CHARACTER SET utf8 DEFAULT NULL
2444+
);
2445+
INSERT INTO t1 VALUES
2446+
('d','d','l','ther'),
2447+
(NULL,'s','NJBIQ','trzetuchv'),
2448+
(-715390976,'coul','MYWFB','cfhtrzetu'),
2449+
(1696792576,'f','i\'s','c'),
2450+
(1,'i','ltpemcfhtr','gsltpemcf'),
2451+
(-663027712,'mgsltpemcf','sa','amgsltpem'),
2452+
(-1686700032,'JPRVK','i','vamgsltpe'),
2453+
(NULL,'STUNB','UNVJV','u'),
2454+
(5,'oka','qyihvamgsl','AXSMD'),
2455+
(NULL,'tqwmqyihva','h','yntqwmqyi'),
2456+
(3,'EGMJN','e','e');
2457+
CREATE TABLE t2 (
2458+
col_varchar varchar(10) DEFAULT NULL,
2459+
col_int INT DEFAULT NULL
2460+
);
2461+
INSERT INTO t2 VALUES ('d',9);
2462+
set optimizer_switch='derived_merge=off,derived_with_keys=on';
2463+
SET @save_heap_size= @@max_heap_table_size;
2464+
SET @@max_heap_table_size= 16384;
2465+
SELECT t2.col_int
2466+
FROM t2
2467+
RIGHT JOIN ( SELECT * FROM t1 ) AS dt
2468+
ON t2.col_varchar = dt.col_varchar
2469+
WHERE t2.col_int IS NOT NULL ;
2470+
col_int
2471+
9
2472+
# Shouldn't use auto_key0 for derived table
2473+
EXPLAIN
2474+
SELECT t2.col_int
2475+
FROM t2
2476+
RIGHT JOIN ( SELECT * FROM t1 ) AS dt
2477+
ON t2.col_varchar = dt.col_varchar
2478+
WHERE t2.col_int IS NOT NULL ;
2479+
id select_type table type possible_keys key key_len ref rows Extra
2480+
1 PRIMARY t2 system NULL NULL NULL NULL 1
2481+
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 11 Using where
2482+
2 DERIVED t1 ALL NULL NULL NULL NULL 11
2483+
SET @@max_heap_table_size= @save_heap_size;
2484+
SET optimizer_switch=@save_optimizer_switch;
2485+
DROP TABLE t1,t2;
2486+
#
23992487
# end of 5.3 tests
24002488
#
24012489
set optimizer_switch=@exit_optimizer_switch;

mysql-test/t/derived_view.test

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,99 @@ deallocate prepare stmt;
17301730
drop table t1,t2;
17311731
set optimizer_switch=@save_optimizer_switch5740;
17321732

1733+
--echo #
1734+
--echo # Bug mdev-5721: possible long key access to a materialized derived table
1735+
--echo # (see also the test case for Bug#13261277 that is actually the same bug)
1736+
--echo #
1737+
1738+
CREATE TABLE t1 (
1739+
id varchar(255) NOT NULL DEFAULT '',
1740+
familyid int(11) DEFAULT NULL,
1741+
withdrawndate date DEFAULT NULL,
1742+
KEY index_td_familyid_id (familyid,id)
1743+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
1744+
1745+
CREATE TABLE t2 (
1746+
id int(11) NOT NULL AUTO_INCREMENT,
1747+
activefromts datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1748+
shortdescription text,
1749+
useraccessfamily varchar(512) DEFAULT NULL,
1750+
serialized longtext,
1751+
PRIMARY KEY (id)
1752+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
1753+
1754+
insert into t1 values ('picture/89/1369722032695.pmd',89,NULL);
1755+
insert into t1 values ('picture/90/1369832057370.pmd',90,NULL);
1756+
insert into t2 values (38,'2013-03-04 07:49:22','desc','CODE','string');
1757+
1758+
EXPLAIN
1759+
SELECT * FROM t2 x,
1760+
(SELECT t2.useraccessfamily, t2.serialized AS picturesubuser, COUNT(*)
1761+
FROM t2, t1 GROUP BY t2.useraccessfamily, picturesubuser) y
1762+
WHERE x.useraccessfamily = y.useraccessfamily;
1763+
1764+
SELECT * FROM t2 x,
1765+
(SELECT t2.useraccessfamily, t2.serialized AS picturesubuser, COUNT(*)
1766+
FROM t2, t1 GROUP BY t2.useraccessfamily, picturesubuser) y
1767+
WHERE x.useraccessfamily = y.useraccessfamily;
1768+
1769+
DROP TABLE t1,t2;
1770+
1771+
--echo #
1772+
--echo # Bug#13261277: Unchecked key length caused missing records.
1773+
--echo #
1774+
1775+
CREATE TABLE t1 (
1776+
col_varchar varchar(1024) CHARACTER SET utf8 DEFAULT NULL,
1777+
stub1 varchar(1024) CHARACTER SET utf8 DEFAULT NULL,
1778+
stub2 varchar(1024) CHARACTER SET utf8 DEFAULT NULL,
1779+
stub3 varchar(1024) CHARACTER SET utf8 DEFAULT NULL
1780+
);
1781+
1782+
INSERT INTO t1 VALUES
1783+
('d','d','l','ther'),
1784+
(NULL,'s','NJBIQ','trzetuchv'),
1785+
(-715390976,'coul','MYWFB','cfhtrzetu'),
1786+
(1696792576,'f','i\'s','c'),
1787+
(1,'i','ltpemcfhtr','gsltpemcf'),
1788+
(-663027712,'mgsltpemcf','sa','amgsltpem'),
1789+
(-1686700032,'JPRVK','i','vamgsltpe'),
1790+
(NULL,'STUNB','UNVJV','u'),
1791+
(5,'oka','qyihvamgsl','AXSMD'),
1792+
(NULL,'tqwmqyihva','h','yntqwmqyi'),
1793+
(3,'EGMJN','e','e');
1794+
1795+
CREATE TABLE t2 (
1796+
col_varchar varchar(10) DEFAULT NULL,
1797+
col_int INT DEFAULT NULL
1798+
);
1799+
1800+
INSERT INTO t2 VALUES ('d',9);
1801+
1802+
set optimizer_switch='derived_merge=off,derived_with_keys=on';
1803+
1804+
SET @save_heap_size= @@max_heap_table_size;
1805+
SET @@max_heap_table_size= 16384;
1806+
1807+
SELECT t2.col_int
1808+
FROM t2
1809+
RIGHT JOIN ( SELECT * FROM t1 ) AS dt
1810+
ON t2.col_varchar = dt.col_varchar
1811+
WHERE t2.col_int IS NOT NULL ;
1812+
1813+
--echo # Shouldn't use auto_key0 for derived table
1814+
EXPLAIN
1815+
SELECT t2.col_int
1816+
FROM t2
1817+
RIGHT JOIN ( SELECT * FROM t1 ) AS dt
1818+
ON t2.col_varchar = dt.col_varchar
1819+
WHERE t2.col_int IS NOT NULL ;
1820+
1821+
SET @@max_heap_table_size= @save_heap_size;
1822+
SET optimizer_switch=@save_optimizer_switch;
1823+
1824+
DROP TABLE t1,t2;
1825+
17331826
--echo #
17341827
--echo # end of 5.3 tests
17351828
--echo #

sql/sql_select.cc

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8977,6 +8977,25 @@ uint get_next_field_for_derived_key(uchar *arg)
89778977
}
89788978

89798979

8980+
static
8981+
uint get_next_field_for_derived_key_simple(uchar *arg)
8982+
{
8983+
KEYUSE *keyuse= *(KEYUSE **) arg;
8984+
if (!keyuse)
8985+
return (uint) (-1);
8986+
TABLE *table= keyuse->table;
8987+
uint key= keyuse->key;
8988+
uint fldno= keyuse->keypart;
8989+
for ( ;
8990+
keyuse->table == table && keyuse->key == key && keyuse->keypart == fldno;
8991+
keyuse++)
8992+
;
8993+
if (keyuse->key != key)
8994+
keyuse= 0;
8995+
*((KEYUSE **) arg)= keyuse;
8996+
return fldno;
8997+
}
8998+
89808999
static
89819000
bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys)
89829001
{
@@ -9007,12 +9026,28 @@ bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys)
90079026
}
90089027
else
90099028
{
9010-
if (table->add_tmp_key(table->s->keys, parts,
9011-
get_next_field_for_derived_key,
9012-
(uchar *) &first_keyuse,
9013-
FALSE))
9014-
return TRUE;
9015-
table->reginfo.join_tab->keys.set_bit(table->s->keys);
9029+
KEYUSE *save_first_keyuse= first_keyuse;
9030+
if (table->check_tmp_key(table->s->keys, parts,
9031+
get_next_field_for_derived_key_simple,
9032+
(uchar *) &first_keyuse))
9033+
9034+
{
9035+
first_keyuse= save_first_keyuse;
9036+
if (table->add_tmp_key(table->s->keys, parts,
9037+
get_next_field_for_derived_key,
9038+
(uchar *) &first_keyuse,
9039+
FALSE))
9040+
return TRUE;
9041+
table->reginfo.join_tab->keys.set_bit(table->s->keys);
9042+
}
9043+
else
9044+
{
9045+
/* Mark keyuses for this key to be excluded */
9046+
for (KEYUSE *curr=save_first_keyuse; curr < first_keyuse; curr++)
9047+
{
9048+
curr->key= MAX_KEY;
9049+
}
9050+
}
90169051
first_keyuse= keyuse;
90179052
key_count++;
90189053
parts= 0;

sql/table.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5439,6 +5439,52 @@ void TABLE::create_key_part_by_field(KEY *keyinfo,
54395439
}
54405440

54415441

5442+
/**
5443+
@brief
5444+
Check validity of a possible key for the derived table
5445+
5446+
@param key the number of the key
5447+
@param key_parts number of components of the key
5448+
@param next_field_no the call-back function that returns the number of
5449+
the field used as the next component of the key
5450+
@param arg the argument for the above function
5451+
5452+
@details
5453+
The function checks whether a possible key satisfies the constraints
5454+
imposed on the keys of any temporary table.
5455+
5456+
@return TRUE if the key is valid
5457+
@return FALSE otherwise
5458+
*/
5459+
5460+
bool TABLE::check_tmp_key(uint key, uint key_parts,
5461+
uint (*next_field_no) (uchar *), uchar *arg)
5462+
{
5463+
Field **reg_field;
5464+
uint i;
5465+
uint key_len= 0;
5466+
5467+
for (i= 0; i < key_parts; i++)
5468+
{
5469+
uint fld_idx= next_field_no(arg);
5470+
reg_field= field + fld_idx;
5471+
uint fld_store_len= (uint16) (*reg_field)->key_length();
5472+
if ((*reg_field)->real_maybe_null())
5473+
fld_store_len+= HA_KEY_NULL_LENGTH;
5474+
if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
5475+
(*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
5476+
(*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
5477+
fld_store_len+= HA_KEY_BLOB_LENGTH;
5478+
key_len+= fld_store_len;
5479+
}
5480+
/*
5481+
We use MI_MAX_KEY_LENGTH (myisam's default) below because it is
5482+
smaller than MAX_KEY_LENGTH (heap's default) and it's unknown whether
5483+
myisam or heap will be used for the temporary table.
5484+
*/
5485+
return key_len <= MI_MAX_KEY_LENGTH;
5486+
}
5487+
54425488
/**
54435489
@brief
54445490
Add one key to a temporary table
@@ -5470,6 +5516,7 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
54705516
KEY* keyinfo;
54715517
Field **reg_field;
54725518
uint i;
5519+
54735520
bool key_start= TRUE;
54745521
KEY_PART_INFO* key_part_info=
54755522
(KEY_PART_INFO*) alloc_root(&mem_root, sizeof(KEY_PART_INFO)*key_parts);

sql/table.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,8 @@ struct st_table {
986986
inline bool needs_reopen_or_name_lock()
987987
{ return s->version != refresh_version; }
988988
bool alloc_keys(uint key_count);
989+
bool check_tmp_key(uint key, uint key_parts,
990+
uint (*next_field_no) (uchar *), uchar *arg);
989991
bool add_tmp_key(uint key, uint key_parts,
990992
uint (*next_field_no) (uchar *), uchar *arg,
991993
bool unique);

0 commit comments

Comments
 (0)