Commit b3c7cf81 authored by Monty's avatar Monty

Fix for MDEV-14141 Crash in print_keydup_error()

May also fix: MDEV-14970 "MariaDB crashed with signal 11 and Aria table"

I am not able to reproduce a crash, however there was no protection in
print_keydup_error() if the storage engine reported the wrong key number.

This patch adds such a protection and should stop any further crashes
in this case.

Other things:
- Added extra protection in Aria to not set errkey to more than number of
  keys. (Don't think this is cause of this crash, but better safe than
  sorry)
- Extend test_if_equal_repl_errors() to handle different cases of
  ER_DUP_ENTRY. This is just mainly precaution for the future.
parent a4663af0
...@@ -2167,7 +2167,7 @@ col1 int(10) NOT NULL ...@@ -2167,7 +2167,7 @@ col1 int(10) NOT NULL
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(t1); ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(t1);
insert into m1 (col1) values (1); insert into m1 (col1) values (1);
insert into m1 (col1) values (1); insert into m1 (col1) values (1);
ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' ERROR 23000: Can't write; duplicate key in table 'm1'
drop table m1, t1; drop table m1, t1;
# #
# Bug#45800 crash when replacing into a merge table and there is a duplicate # Bug#45800 crash when replacing into a merge table and there is a duplicate
...@@ -2204,7 +2204,7 @@ CREATE TABLE m1 (c1 INT, c2 INT, UNIQUE (c1)) ENGINE=MRG_MyISAM INSERT_METHOD=LA ...@@ -2204,7 +2204,7 @@ CREATE TABLE m1 (c1 INT, c2 INT, UNIQUE (c1)) ENGINE=MRG_MyISAM INSERT_METHOD=LA
INSERT INTO m1 VALUES (1,2); INSERT INTO m1 VALUES (1,2);
# insert the duplicate value into the merge table # insert the duplicate value into the merge table
INSERT INTO m1 VALUES (3,2); INSERT INTO m1 VALUES (3,2);
ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' ERROR 23000: Can't write; duplicate key in table 'm1'
DROP TABLE m1,t1; DROP TABLE m1,t1;
# Try to define MERGE and MyISAM with keys on different columns # Try to define MERGE and MyISAM with keys on different columns
CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE (c1)); CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE (c1));
......
...@@ -1559,7 +1559,7 @@ CREATE TABLE m1 ( ...@@ -1559,7 +1559,7 @@ CREATE TABLE m1 (
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(t1); ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(t1);
insert into m1 (col1) values (1); insert into m1 (col1) values (1);
--error ER_DUP_ENTRY --error ER_DUP_KEY
insert into m1 (col1) values (1); insert into m1 (col1) values (1);
drop table m1, t1; drop table m1, t1;
...@@ -1593,7 +1593,7 @@ CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE (c1), UNIQUE (c2)); ...@@ -1593,7 +1593,7 @@ 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); CREATE TABLE m1 (c1 INT, c2 INT, UNIQUE (c1)) ENGINE=MRG_MyISAM INSERT_METHOD=LAST UNION=(t1);
INSERT INTO m1 VALUES (1,2); INSERT INTO m1 VALUES (1,2);
--echo # insert the duplicate value into the merge table --echo # insert the duplicate value into the merge table
--error ER_DUP_ENTRY --error ER_DUP_KEY
INSERT INTO m1 VALUES (3,2); INSERT INTO m1 VALUES (3,2);
DROP TABLE m1,t1; DROP TABLE m1,t1;
......
...@@ -3338,9 +3338,11 @@ void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag) ...@@ -3338,9 +3338,11 @@ void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag)
if (key == NULL) if (key == NULL)
{ {
/* Key is unknown */ /*
str.copy("", 0, system_charset_info); Key is unknown. Should only happen if storage engine reports wrong
my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), "*UNKNOWN*"); duplicate key number.
*/
my_printf_error(ER_DUP_ENTRY, msg, errflag, "", "*UNKNOWN*");
} }
else else
{ {
...@@ -3432,11 +3434,9 @@ void handler::print_error(int error, myf errflag) ...@@ -3432,11 +3434,9 @@ void handler::print_error(int error, myf errflag)
if (table) if (table)
{ {
uint key_nr=get_dup_key(error); uint key_nr=get_dup_key(error);
if ((int) key_nr >= 0) if ((int) key_nr >= 0 && key_nr < table->s->keys)
{ {
print_keydup_error(table, print_keydup_error(table, &table->key_info[key_nr], errflag);
key_nr == MAX_KEY ? NULL : &table->key_info[key_nr],
errflag);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
} }
......
...@@ -4075,8 +4075,13 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error) ...@@ -4075,8 +4075,13 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error)
return 1; return 1;
switch (expected_error) { switch (expected_error) {
case ER_DUP_ENTRY: case ER_DUP_ENTRY:
case ER_DUP_ENTRY_WITH_KEY_NAME:
case ER_DUP_KEY:
case ER_AUTOINC_READ_FAILED: case ER_AUTOINC_READ_FAILED:
return (actual_error == ER_AUTOINC_READ_FAILED || return (actual_error == ER_DUP_ENTRY ||
actual_error == ER_DUP_ENTRY_WITH_KEY_NAME ||
actual_error == ER_DUP_KEY ||
actual_error == ER_AUTOINC_READ_FAILED ||
actual_error == HA_ERR_AUTOINC_ERANGE); actual_error == HA_ERR_AUTOINC_ERANGE);
case ER_UNKNOWN_TABLE: case ER_UNKNOWN_TABLE:
return actual_error == ER_IT_IS_A_VIEW; return actual_error == ER_IT_IS_A_VIEW;
......
...@@ -9612,12 +9612,13 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, ...@@ -9612,12 +9612,13 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
if ((int) key_nr >= 0) if ((int) key_nr >= 0)
{ {
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME); const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
if (key_nr == 0 && if (key_nr == 0 && to->s->keys > 0 &&
(to->key_info[0].key_part[0].field->flags & (to->key_info[0].key_part[0].field->flags &
AUTO_INCREMENT_FLAG)) AUTO_INCREMENT_FLAG))
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE); err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
print_keydup_error(to, key_nr == MAX_KEY ? NULL : print_keydup_error(to,
&to->key_info[key_nr], key_nr >= to->s->keys ? NULL :
&to->key_info[key_nr],
err_msg, MYF(0)); err_msg, MYF(0));
} }
else else
......
...@@ -340,7 +340,7 @@ int maria_write(MARIA_HA *info, uchar *record) ...@@ -340,7 +340,7 @@ int maria_write(MARIA_HA *info, uchar *record)
for (j=0 ; j < share->base.keys ; j++) for (j=0 ; j < share->base.keys ; j++)
maria_flush_bulk_insert(info, j); maria_flush_bulk_insert(info, j);
} }
info->errkey= (int) i; info->errkey= i < share->base.keys ? (int) i : -1;
/* /*
We delete keys in the reverse order of insertion. This is the order that We delete keys in the reverse order of insertion. This is the order that
a rollback would do and is important for CLR_ENDs generated by a rollback would do and is important for CLR_ENDs generated by
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment