Commit b56ad494 authored by Sergei Golubchik's avatar Sergei Golubchik

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)
parent 66fd45af
...@@ -90,7 +90,7 @@ ERROR HY000: Failed to read from the .par file ...@@ -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 ...@@ -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; ...@@ -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; ...@@ -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; ...@@ -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; ...@@ -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 *, ...@@ -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,14 +2317,22 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, ...@@ -2315,14 +2317,22 @@ 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)))
{
/*
it's not an error if the table doesn't exist in the engine.
warn the user, but still report DROP being a success
*/
bool intercept= error == ENOENT || error == HA_ERR_NO_SUCH_TABLE;
if (!intercept || generate_warning)
{ {
/* /*
Because file->print_error() use my_error() to generate the error message Because file->print_error() use my_error() to generate the error message
...@@ -2345,18 +2355,29 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, ...@@ -2345,18 +2355,29 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
file->change_table_ptr(&dummy_table, &dummy_share); file->change_table_ptr(&dummy_table, &dummy_share);
#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); thd->push_internal_handler(&ha_delete_table_error_handler);
file->print_error(error, 0); file->print_error(error, 0);
if (intercept || error == HA_ERR_ROW_IS_REFERENCED)
{
thd->pop_internal_handler(); thd->pop_internal_handler();
if (error == HA_ERR_ROW_IS_REFERENCED)
/* my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
XXX: should we convert *all* errors to warnings here? else
What if the error is fatal?
*/
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, error, push_warning(thd, Sql_condition::WARN_LEVEL_WARN, error,
ha_delete_table_error_handler.buff); ha_delete_table_error_handler.buff);
} }
}
if (intercept)
error= 0;
}
delete file; delete file;
DBUG_RETURN(error); DBUG_RETURN(error);
......
...@@ -2201,15 +2201,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -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, ...@@ -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,12 +2511,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -2518,12 +2511,9 @@ 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;
} }
if (error) if (error)
...@@ -2533,6 +2523,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -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, ...@@ -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: ...@@ -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(),
......
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