MDEV-8287 DROP TABLE suppresses all engine errors
in ha_delete_table() * only convert ENOENT and HA_ERR_NO_SUCH_TABLE to warnings * only return real error codes (that is, not ENOENT and not HA_ERR_NO_SUCH_TABLE) * intercept HA_ERR_ROW_IS_REFERENCED to generate backward compatible ER_ROW_IS_REFERENCED in mysql_rm_table_no_locks() * no special code to handle HA_ERR_ROW_IS_REFERENCED * no special code to handle ENOENT and HA_ERR_NO_SUCH_TABLE * return multi-table error ER_BAD_TABLE_ERROR <table list> only when there were many errors, not when there were many tables to drop (but only one table generated an error)
This commit is contained in:
parent
66fd45afce
commit
b56ad494b4
@ -90,7 +90,7 @@ ERROR HY000: Failed to read from the .par file
|
|||||||
# Note that it is currently impossible to drop a partitioned table
|
# Note that it is currently impossible to drop a partitioned table
|
||||||
# without the .par file
|
# without the .par file
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
ERROR 42S02: Unknown table 'test.t1'
|
ERROR HY000: Got error 1 "Operation not permitted" from storage engine partition
|
||||||
#
|
#
|
||||||
# Bug#50392: insert_id is not reset for partitioned tables
|
# Bug#50392: insert_id is not reset for partitioned tables
|
||||||
# auto_increment on duplicate entry
|
# auto_increment on duplicate entry
|
||||||
|
@ -11,6 +11,6 @@ t1
|
|||||||
SHOW CREATE TABLE t1;
|
SHOW CREATE TABLE t1;
|
||||||
ERROR HY000: Incorrect information in file: './test/t1.frm'
|
ERROR HY000: Incorrect information in file: './test/t1.frm'
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
ERROR 42S02: Unknown table 'test.t1'
|
ERROR HY000: Got error 1 "Operation not permitted" from storage engine partition
|
||||||
t1.frm
|
t1.frm
|
||||||
t1.par
|
t1.par
|
||||||
|
@ -45,7 +45,7 @@ BEGIN;
|
|||||||
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
||||||
ERROR HY000: Can't create table `test`.`t2` (errno: 131 "Command not supported by database")
|
ERROR HY000: Can't create table `test`.`t2` (errno: 131 "Command not supported by database")
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
ERROR 42S02: Unknown table 'test.t1'
|
ERROR HY000: Storage engine InnoDB of the table `test`.`t1` doesn't have this option
|
||||||
TRUNCATE TABLE t1;
|
TRUNCATE TABLE t1;
|
||||||
ERROR HY000: Got error 131 "Command not supported by database" during COMMIT
|
ERROR HY000: Got error 131 "Command not supported by database" during COMMIT
|
||||||
ALTER TABLE t1 ENGINE=MyISAM;
|
ALTER TABLE t1 ENGINE=MyISAM;
|
||||||
|
@ -38,7 +38,7 @@ SET innodb_fake_changes=1;
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
--error 1005
|
--error 1005
|
||||||
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
||||||
--error 1051
|
--error 1031
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
--error 1180
|
--error 1180
|
||||||
TRUNCATE TABLE t1;
|
TRUNCATE TABLE t1;
|
||||||
|
@ -123,7 +123,7 @@ CHECK TABLE t1;
|
|||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
--echo # Note that it is currently impossible to drop a partitioned table
|
--echo # Note that it is currently impossible to drop a partitioned table
|
||||||
--echo # without the .par file
|
--echo # without the .par file
|
||||||
--error ER_BAD_TABLE_ERROR
|
--error ER_GET_ERRNO
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
--remove_file $MYSQLD_DATADIR/test/t1.frm
|
--remove_file $MYSQLD_DATADIR/test/t1.frm
|
||||||
--remove_file $MYSQLD_DATADIR/test/t1#P#p0.MYI
|
--remove_file $MYSQLD_DATADIR/test/t1#P#p0.MYI
|
||||||
|
@ -19,7 +19,7 @@ SHOW TABLES;
|
|||||||
--replace_result $MYSQLD_DATADIR ./
|
--replace_result $MYSQLD_DATADIR ./
|
||||||
--error ER_NOT_FORM_FILE
|
--error ER_NOT_FORM_FILE
|
||||||
SHOW CREATE TABLE t1;
|
SHOW CREATE TABLE t1;
|
||||||
--error ER_BAD_TABLE_ERROR
|
--error ER_GET_ERRNO
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
--list_files $MYSQLD_DATADIR/test t1*
|
--list_files $MYSQLD_DATADIR/test t1*
|
||||||
--remove_file $MYSQLD_DATADIR/test/t1.frm
|
--remove_file $MYSQLD_DATADIR/test/t1.frm
|
||||||
|
@ -2298,9 +2298,11 @@ handle_condition(THD *,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @brief
|
/** delete a table in the engine
|
||||||
This should return ENOENT if the file doesn't exists.
|
|
||||||
The .frm file will be deleted only if we return 0 or ENOENT
|
@note
|
||||||
|
ENOENT and HA_ERR_NO_SUCH_TABLE are not considered errors.
|
||||||
|
The .frm file will be deleted only if we return 0.
|
||||||
*/
|
*/
|
||||||
int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
|
int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
|
||||||
const char *db, const char *alias, bool generate_warning)
|
const char *db, const char *alias, bool generate_warning)
|
||||||
@ -2315,47 +2317,66 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
|
|||||||
/* table_type is NULL in ALTER TABLE when renaming only .frm files */
|
/* table_type is NULL in ALTER TABLE when renaming only .frm files */
|
||||||
if (table_type == NULL || table_type == view_pseudo_hton ||
|
if (table_type == NULL || table_type == view_pseudo_hton ||
|
||||||
! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type)))
|
! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type)))
|
||||||
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
bzero((char*) &dummy_table, sizeof(dummy_table));
|
bzero((char*) &dummy_table, sizeof(dummy_table));
|
||||||
bzero((char*) &dummy_share, sizeof(dummy_share));
|
bzero((char*) &dummy_share, sizeof(dummy_share));
|
||||||
dummy_table.s= &dummy_share;
|
dummy_table.s= &dummy_share;
|
||||||
|
|
||||||
path= get_canonical_filename(file, path, tmp_path);
|
path= get_canonical_filename(file, path, tmp_path);
|
||||||
if ((error= file->ha_delete_table(path)) && generate_warning)
|
if ((error= file->ha_delete_table(path)))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Because file->print_error() use my_error() to generate the error message
|
it's not an error if the table doesn't exist in the engine.
|
||||||
we use an internal error handler to intercept it and store the text
|
warn the user, but still report DROP being a success
|
||||||
in a temporary buffer. Later the message will be presented to user
|
|
||||||
as a warning.
|
|
||||||
*/
|
*/
|
||||||
Ha_delete_table_error_handler ha_delete_table_error_handler;
|
bool intercept= error == ENOENT || error == HA_ERR_NO_SUCH_TABLE;
|
||||||
|
|
||||||
/* Fill up strucutures that print_error may need */
|
if (!intercept || generate_warning)
|
||||||
dummy_share.path.str= (char*) path;
|
{
|
||||||
dummy_share.path.length= strlen(path);
|
/*
|
||||||
dummy_share.normalized_path= dummy_share.path;
|
Because file->print_error() use my_error() to generate the error message
|
||||||
dummy_share.db.str= (char*) db;
|
we use an internal error handler to intercept it and store the text
|
||||||
dummy_share.db.length= strlen(db);
|
in a temporary buffer. Later the message will be presented to user
|
||||||
dummy_share.table_name.str= (char*) alias;
|
as a warning.
|
||||||
dummy_share.table_name.length= strlen(alias);
|
*/
|
||||||
dummy_table.alias.set(alias, dummy_share.table_name.length,
|
Ha_delete_table_error_handler ha_delete_table_error_handler;
|
||||||
table_alias_charset);
|
|
||||||
|
|
||||||
file->change_table_ptr(&dummy_table, &dummy_share);
|
/* Fill up strucutures that print_error may need */
|
||||||
|
dummy_share.path.str= (char*) path;
|
||||||
|
dummy_share.path.length= strlen(path);
|
||||||
|
dummy_share.normalized_path= dummy_share.path;
|
||||||
|
dummy_share.db.str= (char*) db;
|
||||||
|
dummy_share.db.length= strlen(db);
|
||||||
|
dummy_share.table_name.str= (char*) alias;
|
||||||
|
dummy_share.table_name.length= strlen(alias);
|
||||||
|
dummy_table.alias.set(alias, dummy_share.table_name.length,
|
||||||
|
table_alias_charset);
|
||||||
|
|
||||||
thd->push_internal_handler(&ha_delete_table_error_handler);
|
file->change_table_ptr(&dummy_table, &dummy_share);
|
||||||
file->print_error(error, 0);
|
|
||||||
|
|
||||||
thd->pop_internal_handler();
|
#if MYSQL_VERSION_ID > 100105
|
||||||
|
// XXX as an ugly 10.0-only hack we intercept HA_ERR_ROW_IS_REFERENCED,
|
||||||
|
// to report it under the old historical error number.
|
||||||
|
#error remove HA_ERR_ROW_IS_REFERENCED, use ME_JUST_WARNING instead of a handler
|
||||||
|
#endif
|
||||||
|
if (intercept || error == HA_ERR_ROW_IS_REFERENCED)
|
||||||
|
thd->push_internal_handler(&ha_delete_table_error_handler);
|
||||||
|
|
||||||
/*
|
file->print_error(error, 0);
|
||||||
XXX: should we convert *all* errors to warnings here?
|
|
||||||
What if the error is fatal?
|
if (intercept || error == HA_ERR_ROW_IS_REFERENCED)
|
||||||
*/
|
{
|
||||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, error,
|
thd->pop_internal_handler();
|
||||||
ha_delete_table_error_handler.buff);
|
if (error == HA_ERR_ROW_IS_REFERENCED)
|
||||||
|
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
|
||||||
|
else
|
||||||
|
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, error,
|
||||||
|
ha_delete_table_error_handler.buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (intercept)
|
||||||
|
error= 0;
|
||||||
}
|
}
|
||||||
delete file;
|
delete file;
|
||||||
|
|
||||||
|
@ -2201,15 +2201,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
char path[FN_REFLEN + 1], wrong_tables_buff[160], *alias= NULL;
|
char path[FN_REFLEN + 1], wrong_tables_buff[160], *alias= NULL;
|
||||||
String wrong_tables(wrong_tables_buff, sizeof(wrong_tables_buff)-1,
|
String wrong_tables(wrong_tables_buff, sizeof(wrong_tables_buff)-1,
|
||||||
system_charset_info);
|
system_charset_info);
|
||||||
uint path_length= 0;
|
uint path_length= 0, errors= 0;
|
||||||
int error= 0;
|
int error= 0;
|
||||||
int non_temp_tables_count= 0;
|
int non_temp_tables_count= 0;
|
||||||
bool foreign_key_error=0;
|
|
||||||
bool non_tmp_error= 0;
|
bool non_tmp_error= 0;
|
||||||
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
|
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
|
||||||
bool non_tmp_table_deleted= 0;
|
bool non_tmp_table_deleted= 0;
|
||||||
bool is_drop_tmp_if_exists_added= 0;
|
bool is_drop_tmp_if_exists_added= 0;
|
||||||
bool one_table= tables->next_local == 0;
|
|
||||||
bool was_view= 0;
|
bool was_view= 0;
|
||||||
String built_query;
|
String built_query;
|
||||||
String built_trans_tmp_query, built_non_trans_tmp_query;
|
String built_trans_tmp_query, built_non_trans_tmp_query;
|
||||||
@ -2495,12 +2493,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
error= ha_delete_table(thd, table_type, path, db, table->table_name,
|
error= ha_delete_table(thd, table_type, path, db, table->table_name,
|
||||||
!dont_log_query);
|
!dont_log_query);
|
||||||
|
|
||||||
if (error == HA_ERR_ROW_IS_REFERENCED)
|
if (!error)
|
||||||
{
|
|
||||||
/* the table is referenced by a foreign key constraint */
|
|
||||||
foreign_key_error= 1;
|
|
||||||
}
|
|
||||||
if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
|
|
||||||
{
|
{
|
||||||
int frm_delete_error, trigger_drop_error= 0;
|
int frm_delete_error, trigger_drop_error= 0;
|
||||||
/* Delete the table definition file */
|
/* Delete the table definition file */
|
||||||
@ -2518,11 +2511,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
if (trigger_drop_error ||
|
if (trigger_drop_error ||
|
||||||
(frm_delete_error && frm_delete_error != ENOENT))
|
(frm_delete_error && frm_delete_error != ENOENT))
|
||||||
error= 1;
|
error= 1;
|
||||||
else if (!frm_delete_error || !error || if_exists)
|
else if (frm_delete_error && if_exists)
|
||||||
{
|
|
||||||
error= 0;
|
|
||||||
thd->clear_error();
|
thd->clear_error();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
non_tmp_error= error ? TRUE : non_tmp_error;
|
non_tmp_error= error ? TRUE : non_tmp_error;
|
||||||
}
|
}
|
||||||
@ -2533,6 +2523,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
wrong_tables.append(db);
|
wrong_tables.append(db);
|
||||||
wrong_tables.append('.');
|
wrong_tables.append('.');
|
||||||
wrong_tables.append(table->table_name);
|
wrong_tables.append(table->table_name);
|
||||||
|
errors++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2556,14 +2547,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
err:
|
err:
|
||||||
if (wrong_tables.length())
|
if (wrong_tables.length())
|
||||||
{
|
{
|
||||||
if (one_table && was_view)
|
DBUG_ASSERT(errors);
|
||||||
|
if (errors == 1 && was_view)
|
||||||
my_printf_error(ER_IT_IS_A_VIEW, ER(ER_IT_IS_A_VIEW), MYF(0),
|
my_printf_error(ER_IT_IS_A_VIEW, ER(ER_IT_IS_A_VIEW), MYF(0),
|
||||||
wrong_tables.c_ptr_safe());
|
wrong_tables.c_ptr_safe());
|
||||||
else if (!foreign_key_error)
|
else if (errors > 1 || !thd->is_error())
|
||||||
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
|
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
|
||||||
wrong_tables.c_ptr_safe());
|
wrong_tables.c_ptr_safe());
|
||||||
else
|
|
||||||
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
|
|
||||||
error= 1;
|
error= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2614,8 +2604,8 @@ err:
|
|||||||
/* Chop of the last comma */
|
/* Chop of the last comma */
|
||||||
built_query.chop();
|
built_query.chop();
|
||||||
built_query.append(" /* generated by server */");
|
built_query.append(" /* generated by server */");
|
||||||
int error_code = (non_tmp_error ?
|
int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno()
|
||||||
(foreign_key_error ? ER_ROW_IS_REFERENCED : ER_BAD_TABLE_ERROR) : 0);
|
: 0;
|
||||||
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
||||||
built_query.ptr(),
|
built_query.ptr(),
|
||||||
built_query.length(),
|
built_query.length(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user