diff options
-rw-r--r-- | include/myisammrg.h | 1 | ||||
-rw-r--r-- | mysql-test/r/merge.result | 46 | ||||
-rw-r--r-- | mysql-test/t/merge.test | 43 | ||||
-rw-r--r-- | storage/myisammrg/ha_myisammrg.cc | 6 | ||||
-rw-r--r-- | storage/myisammrg/ha_myisammrg.h | 3 | ||||
-rw-r--r-- | storage/myisammrg/myrg_info.c | 18 |
6 files changed, 115 insertions, 2 deletions
diff --git a/include/myisammrg.h b/include/myisammrg.h index 446ecb7d719..31ce3fa47b8 100644 --- a/include/myisammrg.h +++ b/include/myisammrg.h @@ -47,6 +47,7 @@ typedef struct st_mymerge_info /* Struct from h_info */ ulonglong deleted; /* Deleted records in database */ ulonglong recpos; /* Pos for last used record */ ulonglong data_file_length; + ulonglong dupp_key_pos; /* Offset of the Duplicate key in the merge table */ uint reclength; /* Recordlength */ int errkey; /* With key was dupplicated on err */ uint options; /* HA_OPTION_... used */ diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 934085ab796..d3563e9f1c1 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2115,6 +2115,52 @@ insert into m1 (col1) values (1); insert into m1 (col1) values (1); ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' drop table m1, t1; +# +# Bug#45800 crash when replacing into a merge table and there is a duplicate +# +# Replace duplicate value in child table when merge table doesn't have key +CREATE TABLE t1 (c1 INT PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE m1 (c1 INT NOT NULL) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +INSERT INTO m1 VALUES (666); +SELECT * FROM m1; +c1 +666 +# insert the duplicate value into the merge table +REPLACE INTO m1 VALUES (666); +SELECT * FROM m1; +c1 +666 +DROP TABLE m1, t1; +# Insert... on duplicate key update (with duplicate values in the table) +CREATE TABLE t1 (c1 INT PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE m1 (c1 INT NOT NULL) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +INSERT INTO m1 VALUES (666); +SELECT * FROM m1; +c1 +666 +# insert the duplicate value into the merge table +INSERT INTO m1 VALUES (666) ON DUPLICATE KEY UPDATE c1=c1+1; +SELECT * FROM m1; +c1 +667 +DROP TABLE m1, t1; +# Insert duplicate value on MERGE table, where, MERGE has a key but MyISAM has more keys +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE (c1), UNIQUE (c2)); +CREATE TABLE m1 (c1 INT, c2 INT, UNIQUE (c1)) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +INSERT INTO m1 VALUES (1,2); +# insert the duplicate value into the merge table +INSERT INTO m1 VALUES (3,2); +ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' +DROP TABLE m1,t1; +# Try to define MERGE and MyISAM with keys on different columns +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE (c1)); +CREATE TABLE m1 (c1 INT, c2 INT, UNIQUE (c2)) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +# Try accessing the merge table for inserts (error occurs) +INSERT INTO m1 VALUES (1,2); +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +INSERT INTO m1 VALUES (1,4); +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +DROP TABLE m1,t1; CREATE TABLE t1 ( col1 INT(10) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 0d90468fc8d..39c805d2b5b 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1515,6 +1515,49 @@ insert into m1 (col1) values (1); drop table m1, t1; +--echo # +--echo # Bug#45800 crash when replacing into a merge table and there is a duplicate +--echo # + +--echo # Replace duplicate value in child table when merge table doesn't have key +CREATE TABLE t1 (c1 INT PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE m1 (c1 INT NOT NULL) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +INSERT INTO m1 VALUES (666); +SELECT * FROM m1; +--echo # insert the duplicate value into the merge table +REPLACE INTO m1 VALUES (666); +SELECT * FROM m1; +DROP TABLE m1, t1; + +--echo # Insert... on duplicate key update (with duplicate values in the table) +CREATE TABLE t1 (c1 INT PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE m1 (c1 INT NOT NULL) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +INSERT INTO m1 VALUES (666); +SELECT * FROM m1; +--echo # insert the duplicate value into the merge table +INSERT INTO m1 VALUES (666) ON DUPLICATE KEY UPDATE c1=c1+1; +SELECT * FROM m1; +DROP TABLE m1, t1; + +--echo # Insert duplicate value on MERGE table, where, MERGE has a key but MyISAM has more keys +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE (c1), UNIQUE (c2)); +CREATE TABLE m1 (c1 INT, c2 INT, UNIQUE (c1)) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +INSERT INTO m1 VALUES (1,2); +--echo # insert the duplicate value into the merge table +--error ER_DUP_ENTRY +INSERT INTO m1 VALUES (3,2); +DROP TABLE m1,t1; + +--echo # Try to define MERGE and MyISAM with keys on different columns +CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE (c1)); +CREATE TABLE m1 (c1 INT, c2 INT, UNIQUE (c2)) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1); +--echo # Try accessing the merge table for inserts (error occurs) +--error ER_WRONG_MRG_TABLE +INSERT INTO m1 VALUES (1,2); +--error ER_WRONG_MRG_TABLE +INSERT INTO m1 VALUES (1,4); +DROP TABLE m1,t1; + # #Bug #44040 MySQL allows creating a MERGE table upon VIEWs but crashes #when using it diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 19510d0eae1..44469a03ce0 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -884,7 +884,6 @@ int ha_myisammrg::info(uint flag) */ mrg_info.errkey= MAX_KEY; } - errkey= mrg_info.errkey; table->s->keys_in_use.set_prefix(table->s->keys); stats.mean_rec_length= mrg_info.reclength; @@ -934,6 +933,11 @@ int ha_myisammrg::info(uint flag) min(file->keys, table->s->key_parts)); } } + if (flag & HA_STATUS_ERRKEY) + { + errkey= mrg_info.errkey; + my_store_ptr(dup_ref, ref_length, mrg_info.dupp_key_pos); + } return 0; } diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index 21d41c9d75a..790aa15e90a 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -44,7 +44,8 @@ class ha_myisammrg: public handler HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED | HA_ANY_INDEX_MAY_BE_UNIQUE | HA_CAN_BIT_FIELD | HA_HAS_RECORDS | - HA_NO_COPY_ON_ALTER); + HA_NO_COPY_ON_ALTER | + HA_DUPLICATE_POS); } ulong index_flags(uint inx, uint part, bool all_parts) const { diff --git a/storage/myisammrg/myrg_info.c b/storage/myisammrg/myrg_info.c index 7ea2dbf58e3..1930351ec8f 100644 --- a/storage/myisammrg/myrg_info.c +++ b/storage/myisammrg/myrg_info.c @@ -58,9 +58,27 @@ int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag) x->reclength= info->reclength; x->options= info->options; if (current_table) + { + /* + errkey is set to the index number of the myisam tables. But + since the MERGE table can have less keys than the MyISAM + tables, errkey cannot be be used as an index into the key_info + on the server. This value will be overwritten with MAX_KEY by + the MERGE engine. + */ x->errkey= current_table->table->errkey; + /* + Calculate the position of the duplicate key to be the sum of the + offset of the myisam file and the offset into the file at which + the duplicate key is located. + */ + x->dupp_key_pos= current_table->file_offset + current_table->table->dupp_key_pos; + } else + { x->errkey= 0; + x->dupp_key_pos= 0; + } x->rec_per_key = info->rec_per_key_part; } DBUG_RETURN(0); |