summaryrefslogtreecommitdiff
path: root/sql/sql_update.cc
diff options
context:
space:
mode:
authorunknown <mkindahl@dl145h.mysql.com>2007-11-14 11:07:30 +0100
committerunknown <mkindahl@dl145h.mysql.com>2007-11-14 11:07:30 +0100
commit19ef3ae88dd66f4a2fb6d9059ec388f673716063 (patch)
treed9b883b86c3d3cfcacb0ef412b5c6daedc325184 /sql/sql_update.cc
parentc4f94b70bdaa26e9b8782771f079a2dc3c1594d6 (diff)
parent296931c1c7db0f502da7ec34060e2ca5d86bddd3 (diff)
downloadmariadb-git-19ef3ae88dd66f4a2fb6d9059ec388f673716063.tar.gz
Merge dl145h.mysql.com:/data0/mkindahl/mysql-5.1
into dl145h.mysql.com:/data0/mkindahl/mysql-5.1-new-rpl mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/suite/rpl/include/rpl_mixed_dml.inc: Auto merged mysql-test/suite/rpl/r/rpl_bug31076.result: Auto merged mysql-test/suite/rpl/t/rpl_bug31076.test: Auto merged mysql-test/suite/rpl/t/rpl_innodb_bug28430.test: Auto merged mysql-test/suite/rpl_ndb/t/disabled.def: Auto merged sql/field.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/handler.cc: Auto merged sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/log_event_old.cc: Auto merged sql/mysqld.cc: Auto merged sql/slave.cc: Auto merged sql/sp_head.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_insert.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged mysql-test/t/partition.test: Manual merge. BitKeeper/deleted/.del-rpl_row_extraColmaster_ndb.result~a2c64bae75b49d2: Manual merge. mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result: Manual merge. mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result: Manual merge. mysql-test/suite/rpl/t/disabled.def: Manual merge. sql/sql_delete.cc: Manual merge.
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r--sql/sql_update.cc103
1 files changed, 51 insertions, 52 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 46022c9f743..ecb7acda61b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -203,6 +203,7 @@ int mysql_update(THD *thd,
bool need_reopen;
ulonglong id;
List<Item> all_fields;
+ THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_update");
for ( ; ; )
@@ -714,45 +715,25 @@ int mysql_update(THD *thd,
thd->row_count++;
}
dup_key_found= 0;
-
- if (!transactional_table && updated > 0)
- thd->transaction.stmt.modified_non_trans_table= TRUE;
-
-
/*
- todo bug#27571: to avoid asynchronization of `error' and
- `error_code' of binlog event constructor
-
- The concept, which is a bit different for insert(!), is to
- replace `error' assignment with the following lines
-
- killed_status= thd->killed; // get the status of the volatile
-
- Notice: thd->killed is type of "state" whereas the lhs has
- "status" the suffix which translates according to WordNet: a state
- at a particular time - at the time of the end of per-row loop in
- our case. Binlogging ops are conducted with the status.
-
- error= (killed_status == THD::NOT_KILLED)? error : 1;
-
- which applies to most mysql_$query functions.
- Event's constructor will accept `killed_status' as an argument:
-
- Query_log_event qinfo(..., killed_status);
-
- thd->killed might be changed after killed_status had got cached and this
- won't affect binlogging event but other effects remain.
-
- Open issue: In a case the error happened not because of KILLED -
- and then KILLED was caught later still within the loop - we shall
- do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN
- error_code.
+ Caching the killed status to pass as the arg to query event constuctor;
+ The cached value can not change whereas the killed status can
+ (externally) since this point and change of the latter won't affect
+ binlogging.
+ It's assumed that if an error was set in combination with an effective
+ killed status then the error is due to killing.
*/
-
- if (thd->killed && !error)
- error= 1; // Aborted
- else if (will_batch &&
- (loc_error= table->file->exec_bulk_update(&dup_key_found)))
+ killed_status= thd->killed; // get the status of the volatile
+ // simulated killing after the loop must be ineffective for binlogging
+ DBUG_EXECUTE_IF("simulate_kill_bug27571",
+ {
+ thd->killed= THD::KILL_QUERY;
+ };);
+ error= (killed_status == THD::NOT_KILLED)? error : 1;
+
+ if (error &&
+ will_batch &&
+ (loc_error= table->file->exec_bulk_update(&dup_key_found)))
/*
An error has occurred when a batched update was performed and returned
an error indication. It cannot be an allowed duplicate key error since
@@ -774,6 +755,10 @@ int mysql_update(THD *thd,
if (will_batch)
table->file->end_bulk_update();
table->file->try_semi_consistent_read(0);
+
+ if (!transactional_table && updated > 0)
+ thd->transaction.stmt.modified_non_trans_table= TRUE;
+
end_read_record(&info);
delete select;
thd->proc_info= "end";
@@ -797,7 +782,7 @@ int mysql_update(THD *thd,
Sometimes we want to binlog even if we updated no rows, in case user used
it to be sure master and slave are in same state.
*/
- if ((error < 0) || (updated && !transactional_table))
+ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
{
@@ -805,7 +790,7 @@ int mysql_update(THD *thd,
thd->clear_error();
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_table, FALSE) &&
+ transactional_table, FALSE, killed_status) &&
transactional_table)
{
error=1; // Rollback update
@@ -1215,8 +1200,8 @@ multi_update::multi_update(TABLE_LIST *table_list,
:all_tables(table_list), leaves(leaves_list), update_tables(0),
tmp_tables(0), updated(0), found(0), fields(field_list),
values(value_list), table_count(0), copy_field(0),
- handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
- transactional_tables(1), ignore(ignore_arg)
+ handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1),
+ transactional_tables(1), ignore(ignore_arg), error_handled(0)
{}
@@ -1418,7 +1403,6 @@ multi_update::initialize_tables(JOIN *join)
if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
DBUG_RETURN(1);
main_table=join->join_tab->table;
- trans_safe= transactional_tables= main_table->file->has_transactions();
table_to_update= 0;
/* Any update has at least one pair (field, value) */
@@ -1713,12 +1697,14 @@ void multi_update::send_error(uint errcode,const char *err)
/* First send error what ever it is ... */
my_error(errcode, MYF(0), err);
- /* If nothing updated return */
- if (updated == 0) /* the counter might be reset in send_eof */
- return; /* and then the query has been binlogged */
+ /* the error was handled or nothing deleted and no side effects return */
+ if (error_handled ||
+ !thd->transaction.stmt.modified_non_trans_table && !updated)
+ return;
/* Something already updated so we have to invalidate cache */
- query_cache_invalidate3(thd, update_tables, 1);
+ if (updated)
+ query_cache_invalidate3(thd, update_tables, 1);
/*
If all tables that has been updated are trans safe then just do rollback.
If not attempt to do remaining updates.
@@ -1750,12 +1736,16 @@ void multi_update::send_error(uint errcode,const char *err)
*/
if (mysql_bin_log.is_open())
{
+ /*
+ THD::killed status might not have been set ON at time of an error
+ got caught and if happens later the killed error is written
+ into repl event.
+ */
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_tables, FALSE);
}
- if (!trans_safe)
- thd->transaction.all.modified_non_trans_table= TRUE;
+ thd->transaction.all.modified_non_trans_table= TRUE;
}
DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table);
@@ -1947,11 +1937,20 @@ bool multi_update::send_eof()
{
char buff[STRING_BUFFER_USUAL_SIZE];
ulonglong id;
+ THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("multi_update::send_eof");
thd->proc_info="updating reference tables";
- /* Does updates for the last n - 1 tables, returns 0 if ok */
+ /*
+ Does updates for the last n - 1 tables, returns 0 if ok;
+ error takes into account killed status gained in do_updates()
+ */
int local_error = (table_count) ? do_updates(0) : 0;
+ /*
+ if local_error is not set ON until after do_updates() then
+ later carried out killing should not affect binlogging.
+ */
+ killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
thd->proc_info= "end";
/* We must invalidate the query cache before binlog writing and
@@ -1978,11 +1977,9 @@ bool multi_update::send_eof()
{
if (local_error == 0)
thd->clear_error();
- else
- updated= 0; /* if there's an error binlog it here not in ::send_error */
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_tables, FALSE) &&
+ transactional_tables, FALSE, killed_status) &&
trans_safe)
{
local_error= 1; // Rollback update
@@ -1991,6 +1988,8 @@ bool multi_update::send_eof()
if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE;
}
+ if (local_error != 0)
+ error_handled= TRUE; // to force early leave from ::send_error()
if (transactional_tables)
{