Rewrite IGNORE handling:

- Instead of supressing all errors, only suppress safe ones like:
ER_DUP_KEY, ER_BAD_NULL_ERROR, ER_SUBQUERY_NO_1_ROW, ER_ROW_IS_REFERENCED_2
This commit is contained in:
Michael Widenius 2011-12-11 18:39:33 +02:00
parent 6d4224a31c
commit 1485874619
10 changed files with 66 additions and 106 deletions

View file

@ -2853,7 +2853,7 @@ void handler::print_error(int error, myf errflag)
str.length(max_length-4);
str.append(STRING_WITH_LEN("..."));
}
my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table_share->table_name.str,
my_error(ER_FOREIGN_DUPLICATE_KEY, errflag, table_share->table_name.str,
str.c_ptr_safe(), key_nr+1);
DBUG_VOID_RETURN;
}
@ -2861,7 +2861,7 @@ void handler::print_error(int error, myf errflag)
break;
}
case HA_ERR_NULL_IN_SPATIAL:
my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, errflag);
DBUG_VOID_RETURN;
case HA_ERR_FOUND_DUPP_UNIQUE:
textno=ER_DUP_UNIQUE;
@ -2931,21 +2931,21 @@ void handler::print_error(int error, myf errflag)
{
String str;
get_error_message(error, &str);
my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
my_error(ER_ROW_IS_REFERENCED_2, errflag, str.c_ptr_safe());
DBUG_VOID_RETURN;
}
case HA_ERR_NO_REFERENCED_ROW:
{
String str;
get_error_message(error, &str);
my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
my_error(ER_NO_REFERENCED_ROW_2, errflag, str.c_ptr_safe());
DBUG_VOID_RETURN;
}
case HA_ERR_TABLE_DEF_CHANGED:
textno=ER_TABLE_DEF_CHANGED;
break;
case HA_ERR_NO_SUCH_TABLE:
my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str,
my_error(ER_NO_SUCH_TABLE, errflag, table_share->db.str,
table_share->table_name.str);
DBUG_VOID_RETURN;
case HA_ERR_RBR_LOGGING_FAILED:
@ -2957,7 +2957,7 @@ void handler::print_error(int error, myf errflag)
uint key_nr= get_dup_key(error);
if ((int) key_nr >= 0)
ptr= table->key_info[key_nr].name;
my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
my_error(ER_DROP_INDEX_FK, errflag, ptr);
DBUG_VOID_RETURN;
}
case HA_ERR_TABLE_NEEDS_UPGRADE:
@ -2986,12 +2986,12 @@ void handler::print_error(int error, myf errflag)
{
const char* engine= table_type();
if (temporary)
my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.c_ptr(),
my_error(ER_GET_TEMPORARY_ERRMSG, errflag, error, str.c_ptr(),
engine);
else
{
SET_FATAL_ERROR;
my_error(ER_GET_ERRMSG, MYF(0), error, str.c_ptr(), engine);
my_error(ER_GET_ERRMSG, errflag, error, str.c_ptr(), engine);
}
}
else
@ -2999,7 +2999,11 @@ void handler::print_error(int error, myf errflag)
DBUG_VOID_RETURN;
}
}
if (fatal_error && (debug_assert_if_crashed_table ||
if (fatal_error)
{
/* Ensure this becomes a true error */
errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO);
if ((debug_assert_if_crashed_table ||
global_system_variables.log_warnings > 1))
{
/*
@ -3007,7 +3011,7 @@ void handler::print_error(int error, myf errflag)
*/
errflag|= ME_NOREFRESH;
}
}
my_error(textno, errflag, table_share->table_name.str, error);
DBUG_ASSERT(!fatal_error || !debug_assert_if_crashed_table);
DBUG_VOID_RETURN;

View file

@ -3187,22 +3187,6 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
thd->is_slave_error= 1; // needed to catch query errors during replication
/*
thd->lex->current_select == 0 if lex structure is not inited
(not query command (COM_QUERY))
*/
if (thd->lex->current_select &&
thd->lex->current_select->no_error && !thd->is_fatal_error)
{
DBUG_PRINT("error",
("Error converted to warning: current_select: no_error %d "
"fatal_error: %d",
(thd->lex->current_select ?
thd->lex->current_select->no_error : 0),
(int) thd->is_fatal_error));
}
else
{
if (thd->main_da.is_ok() && !thd->main_da.can_overwrite_status)
{
/*
@ -3221,7 +3205,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
thd->main_da.set_error_status(thd, error, str);
}
query_cache_abort(&thd->net);
}
/*
If a continue handler is found, the error message will be cleared
by the stored procedures code.

View file

@ -8549,9 +8549,11 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
Item *value, *fld;
Item_field *field;
TABLE *table= 0, *vcol_table= 0;
bool abort_on_warning_saved= thd->abort_on_warning;
bool save_abort_on_warning= thd->abort_on_warning;
bool save_no_errors= thd->no_errors;
DBUG_ENTER("fill_record");
thd->no_errors= ignore_errors;
/*
Reset the table->auto_increment_field_not_null as it is valid for
only one row.
@ -8596,7 +8598,7 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
ER(ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN),
rfield->field_name, table->s->table_name.str);
}
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
if ((value->save_in_field(rfield, 0)) < 0 && !ignore_errors)
{
my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
goto err;
@ -8614,10 +8616,13 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
goto err;
}
}
thd->abort_on_warning= abort_on_warning_saved;
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
DBUG_RETURN(thd->is_error());
err:
thd->abort_on_warning= abort_on_warning_saved;
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
if (table)
table->auto_increment_field_not_null= FALSE;
DBUG_RETURN(TRUE);

View file

@ -2585,7 +2585,8 @@ int select_singlerow_subselect::send_data(List<Item> &items)
Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
if (it->assigned())
{
my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW),
MYF(current_thd->lex->ignore ? ME_JUST_WARNING : 0));
DBUG_RETURN(1);
}
if (unit->offset_limit_cnt)
@ -3830,16 +3831,6 @@ void mark_transaction_to_rollback(THD *thd, bool all)
{
thd->is_fatal_sub_stmt_error= TRUE;
thd->transaction_rollback_request= all;
/*
Aborted transactions can not be IGNOREd.
Switch off the IGNORE flag for the current
SELECT_LEX. This should allow my_error()
to report the error and abort the execution
flow, even in presence
of IGNORE clause.
*/
if (thd->lex->current_select)
thd->lex->current_select->no_error= FALSE;
}
}
/***************************************************************************

View file

@ -124,8 +124,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE);
}
select_lex->no_error= thd->lex->ignore;
const_cond_result= const_cond && (!conds || conds->val_int());
if (thd->is_error())
{
@ -365,16 +363,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
else
{
table->file->print_error(error,MYF(0));
/*
In < 4.0.14 we set the error number to 0 here, but that
was not sensible, because then MySQL would not roll back the
failed DELETE, and also wrote it to the binlog. For MyISAM
tables a DELETE probably never should fail (?), but for
InnoDB it can fail in a FOREIGN KEY error or an
out-of-tablespace error.
*/
if (!select_lex->no_error)
table->file->print_error(error,
MYF(thd->lex->ignore ? ME_JUST_WARNING : 0));
if (thd->is_error())
{
error= 1;
break;
@ -809,7 +800,7 @@ int multi_delete::send_data(List<Item> &values)
TABLE_LIST *del_table;
DBUG_ENTER("multi_delete::send_data");
bool ignore= thd->lex->current_select->no_error;
bool ignore= thd->lex->ignore;
for (del_table= delete_tables;
del_table;
@ -958,11 +949,11 @@ int multi_delete::do_deletes()
table_being_deleted= table_being_deleted->next_local, counter++)
{
TABLE *table = table_being_deleted->table;
int local_error;
if (tempfiles[counter]->get(table))
DBUG_RETURN(1);
int local_error=
do_table_deletes(table, thd->lex->current_select->no_error);
local_error= do_table_deletes(table, thd->lex->ignore);
if (thd->killed && !local_error)
DBUG_RETURN(1);

View file

@ -1579,11 +1579,12 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
else
error= 0;
/*
If ON DUP KEY UPDATE updates a row instead of inserting one, it's
like a regular UPDATE statement: it should not affect the value of a
next SELECT LAST_INSERT_ID() or mysql_insert_id().
Except if LAST_INSERT_ID(#) was in the INSERT query, which is
handled separately by THD::arg_of_last_insert_id_function.
If ON DUP KEY UPDATE updates a row instead of inserting
one, it's like a regular UPDATE statement: it should not
affect the value of a next SELECT LAST_INSERT_ID() or
mysql_insert_id(). Except if LAST_INSERT_ID(#) was in the
INSERT query, which is handled separately by
THD::arg_of_last_insert_id_function.
*/
insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0;
trg_error= (table->triggers &&
@ -1660,11 +1661,12 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
}
/*
If more than one iteration of the above while loop is done, from the second
one the row being inserted will have an explicit value in the autoinc field,
which was set at the first call of handler::update_auto_increment(). This
value is saved to avoid thd->insert_id_for_cur_row becoming 0. Use this saved
autoinc value.
If more than one iteration of the above while loop is done, from
the second one the row being inserted will have an explicit
value in the autoinc field, which was set at the first call of
handler::update_auto_increment(). This value is saved to avoid
thd->insert_id_for_cur_row becoming 0. Use this saved autoinc
value.
*/
if (table->file->insert_id_for_cur_row == 0)
table->file->insert_id_for_cur_row= insert_id_for_cur_row;
@ -1704,9 +1706,6 @@ ok_or_after_trg_err:
err:
info->last_errno= error;
/* current_select is NULL if this is a delayed insert */
if (thd->lex->current_select)
thd->lex->current_select->no_error= 0; // Give error
table->file->print_error(error,MYF(0));
before_trg_err:
@ -3078,8 +3077,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
/* Errors during check_insert_fields() should not be ignored. */
lex->current_select->no_error= FALSE;
res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
check_insert_fields(thd, table_list, *fields, values,
!insert_into_view, 1, &map));
@ -3213,8 +3210,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (!res)
prepare_triggers_for_insert_stmt(table);
lex->current_select->no_error= lex->ignore;
DBUG_RETURN(res);
}

View file

@ -1572,7 +1572,7 @@ void st_select_lex_node::init_query()
options= 0;
sql_cache= SQL_CACHE_UNSPECIFIED;
linkage= UNSPECIFIED_TYPE;
no_error= no_table_names_allowed= 0;
no_table_names_allowed= 0;
uncacheable= 0;
}

View file

@ -429,7 +429,6 @@ public:
uint8 uncacheable;
enum sub_select_type linkage;
bool no_table_names_allowed; /* used for global order by */
bool no_error; /* suppress error message (convert it to warnings) */
static void *operator new(size_t size) throw ()
{

View file

@ -2460,9 +2460,6 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
for (order= sl->order_list.first; order; order= order->next)
order->item= &order->item_ptr;
sl->handle_derived(lex, DT_REINIT);
/* clear the no_error flag for INSERT/UPDATE IGNORE */
sl->no_error= FALSE;
}
{
SELECT_LEX_UNIT *unit= sl->master_unit();

View file

@ -284,7 +284,6 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
}
DBUG_PRINT("info",("res: %d report_error: %d", res,
thd->is_error()));
DBUG_ASSERT(res == 0 || thd->is_error());
res|= thd->is_error();
if (unlikely(res))
result->abort();
@ -1615,9 +1614,6 @@ JOIN::optimize()
error= 0;
// Ignore errors of execution if option IGNORE present
if (thd->lex->ignore)
thd->lex->current_select->no_error= 1;
DBUG_RETURN(0);
setup_subq_exit:
@ -9602,8 +9598,6 @@ bool error_if_full_join(JOIN *join)
{
if (tab->type == JT_ALL && (!tab->select || !tab->select->quick))
{
/* This error should not be ignored. */
join->select_lex->no_error= FALSE;
my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
return(1);