Commit ba4682ae authored by unknown's avatar unknown

Bug #29157: UPDATE, changed rows incorrect

Sometimes the number of really updated rows (with changed
column values) cannot be determined at the server level
alone (e.g. if the storage engine does not return enough
column values to verify that). So the only dependable way
in such cases is to let the storage engine return that
information if possible.
Fixed the bug at server level by providing a way for the 
storage engine to return information about wether it 
actually updated the row or the old and the new column 
values are the same. It can do that by returning 
HA_ERR_RECORD_IS_THE_SAME in ha_update_row().
Note that each storage engine may choose not to try to
return this status code, so this behaviour remains 
storage engine specific.


include/my_base.h:
  Bug #29157: handle the row not updated special return value
sql/log_event.cc:
  Bug #29157: handle the row not updated special return value
sql/sp.cc:
  Bug #29157: handle the row not updated special return value
sql/sql_acl.cc:
  Bug #29157: handle the row not updated special return value
sql/sql_insert.cc:
  Bug #29157: handle the row not updated special return value
sql/sql_servers.cc:
  Bug #29157: handle the row not updated special return value
sql/sql_update.cc:
  Bug #29157: handle the row not updated special return value
parent 28187da7
...@@ -396,7 +396,9 @@ enum ha_base_keytype { ...@@ -396,7 +396,9 @@ enum ha_base_keytype {
#define HA_ERR_AUTOINC_READ_FAILED 166 /* Failed to get next autoinc value */ #define HA_ERR_AUTOINC_READ_FAILED 166 /* Failed to get next autoinc value */
#define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set row autoinc value */ #define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set row autoinc value */
#define HA_ERR_GENERIC 168 /* Generic error */ #define HA_ERR_GENERIC 168 /* Generic error */
#define HA_ERR_LAST 168 /*Copy last error nr.*/ #define HA_ERR_RECORD_IS_THE_SAME 169 /* row not actually updated :
new values same as the old values */
#define HA_ERR_LAST 169 /*Copy last error nr.*/
/* Add error numbers before HA_ERR_LAST and change it accordingly. */ /* Add error numbers before HA_ERR_LAST and change it accordingly. */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
......
...@@ -7171,8 +7171,10 @@ replace_record(THD *thd, TABLE *table, ...@@ -7171,8 +7171,10 @@ replace_record(THD *thd, TABLE *table,
{ {
error=table->file->ha_update_row(table->record[1], error=table->file->ha_update_row(table->record[1],
table->record[0]); table->record[0]);
if (error) if (error && error != HA_ERR_RECORD_IS_THE_SAME)
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
else
error= 0;
DBUG_RETURN(error); DBUG_RETURN(error);
} }
else else
...@@ -7856,6 +7858,8 @@ int Update_rows_log_event::do_exec_row(TABLE *table) ...@@ -7856,6 +7858,8 @@ int Update_rows_log_event::do_exec_row(TABLE *table)
database into the after image delivered from the master. database into the after image delivered from the master.
*/ */
error= table->file->ha_update_row(table->record[1], table->record[0]); error= table->file->ha_update_row(table->record[1], table->record[0]);
if (error == HA_ERR_RECORD_IS_THE_SAME)
error= 0;
return error; return error;
} }
......
...@@ -715,8 +715,11 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) ...@@ -715,8 +715,11 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str, table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str,
chistics->comment.length, chistics->comment.length,
system_charset_info); system_charset_info);
if ((table->file->ha_update_row(table->record[1],table->record[0]))) if ((ret= table->file->ha_update_row(table->record[1],table->record[0])) &&
ret != HA_ERR_RECORD_IS_THE_SAME)
ret= SP_WRITE_ROW_FAILED; ret= SP_WRITE_ROW_FAILED;
else
ret= 0;
} }
if (ret == SP_OK) if (ret == SP_OK)
......
...@@ -1825,7 +1825,8 @@ static bool update_user_table(THD *thd, TABLE *table, ...@@ -1825,7 +1825,8 @@ static bool update_user_table(THD *thd, TABLE *table,
} }
store_record(table,record[1]); store_record(table,record[1]);
table->field[2]->store(new_password, new_password_len, system_charset_info); table->field[2]->store(new_password, new_password_len, system_charset_info);
if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) if ((error=table->file->ha_update_row(table->record[1],table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
{ {
table->file->print_error(error,MYF(0)); /* purecov: deadcode */ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -2041,13 +2042,19 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, ...@@ -2041,13 +2042,19 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
We should NEVER delete from the user table, as a uses can still We should NEVER delete from the user table, as a uses can still
use mysqld even if he doesn't have any privileges in the user table! use mysqld even if he doesn't have any privileges in the user table!
*/ */
if (cmp_record(table,record[1]) && if (cmp_record(table,record[1]))
(error=table->file->ha_update_row(table->record[1],table->record[0]))) {
if ((error=
table->file->ha_update_row(table->record[1],table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
{ // This should never happen { // This should never happen
table->file->print_error(error,MYF(0)); /* purecov: deadcode */ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
error= -1; /* purecov: deadcode */ error= -1; /* purecov: deadcode */
goto end; /* purecov: deadcode */ goto end; /* purecov: deadcode */
} }
else
error= 0;
}
} }
else if ((error=table->file->ha_write_row(table->record[0]))) // insert else if ((error=table->file->ha_write_row(table->record[0]))) // insert
{ // This should never happen { // This should never happen
...@@ -2161,7 +2168,8 @@ static int replace_db_table(TABLE *table, const char *db, ...@@ -2161,7 +2168,8 @@ static int replace_db_table(TABLE *table, const char *db,
if (rights) if (rights)
{ {
if ((error= table->file->ha_update_row(table->record[1], if ((error= table->file->ha_update_row(table->record[1],
table->record[0]))) table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
goto table_error; /* purecov: deadcode */ goto table_error; /* purecov: deadcode */
} }
else /* must have been a revoke of all privileges */ else /* must have been a revoke of all privileges */
...@@ -2543,12 +2551,14 @@ static int replace_column_table(GRANT_TABLE *g_t, ...@@ -2543,12 +2551,14 @@ static int replace_column_table(GRANT_TABLE *g_t,
error=table->file->ha_update_row(table->record[1],table->record[0]); error=table->file->ha_update_row(table->record[1],table->record[0]);
else else
error=table->file->ha_delete_row(table->record[1]); error=table->file->ha_delete_row(table->record[1]);
if (error) if (error && error != HA_ERR_RECORD_IS_THE_SAME)
{ {
table->file->print_error(error,MYF(0)); /* purecov: inspected */ table->file->print_error(error,MYF(0)); /* purecov: inspected */
result= -1; /* purecov: inspected */ result= -1; /* purecov: inspected */
goto end; /* purecov: inspected */ goto end; /* purecov: inspected */
} }
else
error= 0;
grant_column= column_hash_search(g_t, column->column.ptr(), grant_column= column_hash_search(g_t, column->column.ptr(),
column->column.length()); column->column.length());
if (grant_column) // Should always be true if (grant_column) // Should always be true
...@@ -2608,7 +2618,8 @@ static int replace_column_table(GRANT_TABLE *g_t, ...@@ -2608,7 +2618,8 @@ static int replace_column_table(GRANT_TABLE *g_t,
{ {
int tmp_error; int tmp_error;
if ((tmp_error=table->file->ha_update_row(table->record[1], if ((tmp_error=table->file->ha_update_row(table->record[1],
table->record[0]))) table->record[0])) &&
tmp_error != HA_ERR_RECORD_IS_THE_SAME)
{ /* purecov: deadcode */ { /* purecov: deadcode */
table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */ table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
result= -1; /* purecov: deadcode */ result= -1; /* purecov: deadcode */
...@@ -2730,7 +2741,9 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, ...@@ -2730,7 +2741,9 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
{ {
if (store_table_rights || store_col_rights) if (store_table_rights || store_col_rights)
{ {
if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) if ((error=table->file->ha_update_row(table->record[1],
table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
goto table_error; /* purecov: deadcode */ goto table_error; /* purecov: deadcode */
} }
else if ((error = table->file->ha_delete_row(table->record[1]))) else if ((error = table->file->ha_delete_row(table->record[1])))
...@@ -2848,7 +2861,9 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, ...@@ -2848,7 +2861,9 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
{ {
if (store_proc_rights) if (store_proc_rights)
{ {
if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) if ((error=table->file->ha_update_row(table->record[1],
table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
goto table_error; goto table_error;
} }
else if ((error= table->file->ha_delete_row(table->record[1]))) else if ((error= table->file->ha_delete_row(table->record[1])))
...@@ -4914,8 +4929,12 @@ static int modify_grant_table(TABLE *table, Field *host_field, ...@@ -4914,8 +4929,12 @@ static int modify_grant_table(TABLE *table, Field *host_field,
system_charset_info); system_charset_info);
user_field->store(user_to->user.str, user_to->user.length, user_field->store(user_to->user.str, user_to->user.length,
system_charset_info); system_charset_info);
if ((error= table->file->ha_update_row(table->record[1], table->record[0]))) if ((error= table->file->ha_update_row(table->record[1],
table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
else
error= 0;
} }
else else
{ {
......
...@@ -1423,7 +1423,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1423,7 +1423,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
compare_record(table)) compare_record(table))
{ {
if ((error=table->file->ha_update_row(table->record[1], if ((error=table->file->ha_update_row(table->record[1],
table->record[0]))) table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
{ {
if (info->ignore && if (info->ignore &&
!table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) !table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
...@@ -1433,7 +1434,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1433,7 +1434,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
goto err; goto err;
} }
if (error != HA_ERR_RECORD_IS_THE_SAME)
info->updated++; info->updated++;
else
error= 0;
/* /*
If ON DUP KEY UPDATE updates a row instead of inserting one, it's 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 like a regular UPDATE statement: it should not affect the value of a
...@@ -1481,9 +1485,13 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1481,9 +1485,13 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
(!table->triggers || !table->triggers->has_delete_triggers())) (!table->triggers || !table->triggers->has_delete_triggers()))
{ {
if ((error=table->file->ha_update_row(table->record[1], if ((error=table->file->ha_update_row(table->record[1],
table->record[0]))) table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
goto err; goto err;
if (error != HA_ERR_RECORD_IS_THE_SAME)
info->deleted++; info->deleted++;
else
error= 0;
thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row); thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);
/* /*
Since we pretend that we have done insert we should call Since we pretend that we have done insert we should call
......
...@@ -872,11 +872,15 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server) ...@@ -872,11 +872,15 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server)
/* ok, so we can update since the record exists in the table */ /* ok, so we can update since the record exists in the table */
store_record(table,record[1]); store_record(table,record[1]);
store_server_fields(table, server); store_server_fields(table, server);
if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) if ((error=table->file->ha_update_row(table->record[1],
table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
{ {
DBUG_PRINT("info",("problems with ha_update_row %d", error)); DBUG_PRINT("info",("problems with ha_update_row %d", error));
goto end; goto end;
} }
else
error= 0;
} }
end: end:
......
...@@ -548,9 +548,12 @@ int mysql_update(THD *thd, ...@@ -548,9 +548,12 @@ int mysql_update(THD *thd,
error= table->file->ha_update_row(table->record[1], error= table->file->ha_update_row(table->record[1],
table->record[0]); table->record[0]);
} }
if (!error) if (!error || error == HA_ERR_RECORD_IS_THE_SAME)
{ {
if (error != HA_ERR_RECORD_IS_THE_SAME)
updated++; updated++;
else
error= 0;
thd->no_trans_update.stmt= !transactional_table; thd->no_trans_update.stmt= !transactional_table;
if (table->triggers && if (table->triggers &&
...@@ -1524,7 +1527,8 @@ bool multi_update::send_data(List<Item> &not_used_values) ...@@ -1524,7 +1527,8 @@ bool multi_update::send_data(List<Item> &not_used_values)
main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE); main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE);
} }
if ((error=table->file->ha_update_row(table->record[1], if ((error=table->file->ha_update_row(table->record[1],
table->record[0]))) table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
{ {
updated--; updated--;
if (!ignore || if (!ignore ||
...@@ -1542,6 +1546,11 @@ bool multi_update::send_data(List<Item> &not_used_values) ...@@ -1542,6 +1546,11 @@ bool multi_update::send_data(List<Item> &not_used_values)
} }
else else
{ {
if (error == HA_ERR_RECORD_IS_THE_SAME)
{
error= 0;
updated--;
}
/* non-transactional or transactional table got modified */ /* non-transactional or transactional table got modified */
/* either multi_update class' flag is raised in its branch */ /* either multi_update class' flag is raised in its branch */
if (table->file->has_transactions()) if (table->file->has_transactions())
...@@ -1768,13 +1777,17 @@ int multi_update::do_updates(bool from_send_error) ...@@ -1768,13 +1777,17 @@ int multi_update::do_updates(bool from_send_error)
goto err; goto err;
} }
if ((local_error=table->file->ha_update_row(table->record[1], if ((local_error=table->file->ha_update_row(table->record[1],
table->record[0]))) table->record[0])) &&
local_error != HA_ERR_RECORD_IS_THE_SAME)
{ {
if (!ignore || if (!ignore ||
table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY)) table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY))
goto err; goto err;
} }
if (local_error != HA_ERR_RECORD_IS_THE_SAME)
updated++; updated++;
else
local_error= 0;
if (table->triggers && if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
......
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