diff options
author | gkodinov/kgeorge@magare.gmz <> | 2007-07-30 18:27:36 +0300 |
---|---|---|
committer | gkodinov/kgeorge@magare.gmz <> | 2007-07-30 18:27:36 +0300 |
commit | 9a0e6ec6d2aadd14badb65aa6e5c313ce72e276e (patch) | |
tree | 3a0bd3810b778a710ddd3bc97e13539062f58cdc /sql/sql_insert.cc | |
parent | b6bb988d12f7df7033cbb9cebc58036d264ad26e (diff) | |
download | mariadb-git-9a0e6ec6d2aadd14badb65aa6e5c313ce72e276e.tar.gz |
(pushing for Andrei)
Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack
Once had been set the flag might later got reset inside of a stored routine
execution stack.
The reason was in that there was no check if a new statement started at time
of resetting.
The artifact affects most of binlogable DML queries. Notice, that multi-update
is wrapped up within
bug@27716 fix, multi-delete bug@29136.
Fixed with saving parent's statement flag of whether the statement modified
non-transactional table, and unioning (merging) the value with that was gained
in mysql_execute_command.
Resettling thd->no_trans_update members into thd->transaction.`member`;
Asserting code;
Effectively the following properties are held.
1. At the end of a substatement thd->transaction.stmt.modified_non_trans_table
reflects the fact if such a table got modified by the substatement.
That also respects THD::really_abort_on_warnin() requirements.
2. Eventually thd->transaction.stmt.modified_non_trans_table will be computed as
the union of the values of all invoked sub-statements.
That fixes this bug#27417;
Computing of thd->transaction.all.modified_non_trans_table is refined to base to
the stmt's value for all the case including insert .. select statement which
before the patch had an extra issue bug@28960.
Minor issues are covered with mysql_load, mysql_delete, and binloggin of insert in
to temp_table select.
The supplied test verifies limitely, mostly asserts. The ultimate testing is defered
for bug@13270, bug@23333.
Diffstat (limited to 'sql/sql_insert.cc')
-rw-r--r-- | sql/sql_insert.cc | 43 |
1 files changed, 24 insertions, 19 deletions
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 5ba1e766947..5edce08e481 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -733,7 +733,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode) table->file->start_bulk_insert(values_list.elements); - thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); @@ -907,10 +906,12 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (mysql_bin_log.write(&qinfo) && transactional_table) error=1; } - if (!transactional_table && changed) - thd->no_trans_update.all= TRUE; + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } } + DBUG_ASSERT(transactional_table || !changed || + thd->transaction.stmt.modified_non_trans_table); if (transactional_table) error=ha_autocommit_or_rollback(thd,error); @@ -1311,7 +1312,7 @@ static int last_uniq_key(TABLE *table,uint keynr) then both on update triggers will work instead. Similarly both on delete triggers will be invoked if we will delete conflicting records. - Sets thd->no_trans_update.stmt to TRUE if table which is updated didn't have + Sets thd->transaction.stmt.modified_non_trans_table to TRUE if table which is updated didn't have transactions. RETURN VALUE @@ -1478,7 +1479,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) goto err; info->deleted++; if (!table->file->has_transactions()) - thd->no_trans_update.stmt= TRUE; + thd->transaction.stmt.modified_non_trans_table= TRUE; if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_AFTER, TRUE)) @@ -1510,7 +1511,7 @@ ok_or_after_trg_err: if (key) my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH); if (!table->file->has_transactions()) - thd->no_trans_update.stmt= TRUE; + thd->transaction.stmt.modified_non_trans_table= TRUE; DBUG_RETURN(trg_error); err: @@ -2790,7 +2791,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) } if (info.handle_duplicates == DUP_UPDATE) table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE); - thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!info.ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | @@ -2927,7 +2927,8 @@ void select_insert::send_error(uint errcode,const char *err) bool select_insert::send_eof() { - int error,error2; + int error, error2; + bool changed, transactional_table= table->file->has_transactions(); DBUG_ENTER("select_insert::send_eof"); error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0; @@ -2939,12 +2940,14 @@ bool select_insert::send_eof() and ha_autocommit_or_rollback */ - if (info.copied || info.deleted || info.updated) + if (changed= (info.copied || info.deleted || info.updated)) { query_cache_invalidate3(thd, table, 1); - if (!(table->file->has_transactions() || table->s->tmp_table)) - thd->no_trans_update.all= TRUE; + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } + DBUG_ASSERT(transactional_table || !changed || + thd->transaction.stmt.modified_non_trans_table); if (last_insert_id) thd->insert_id(info.copied ? last_insert_id : 0); // For binary log @@ -2954,7 +2957,7 @@ bool select_insert::send_eof() if (!error) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - table->file->has_transactions(), FALSE); + transactional_table, FALSE); mysql_bin_log.write(&qinfo); } if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) @@ -2980,6 +2983,7 @@ bool select_insert::send_eof() void select_insert::abort() { + bool changed, transactional_table; DBUG_ENTER("select_insert::abort"); if (!table) @@ -2990,6 +2994,7 @@ void select_insert::abort() */ DBUG_VOID_RETURN; } + transactional_table= table->file->has_transactions(); if (!thd->prelocked_mode) table->file->end_bulk_insert(); /* @@ -2998,21 +3003,22 @@ void select_insert::abort() error while inserting into a MyISAM table) we must write to the binlog (and the error code will make the slave stop). */ - if ((info.copied || info.deleted || info.updated) && - !table->file->has_transactions()) + if ((changed= info.copied || info.deleted || info.updated) && + !transactional_table) { if (last_insert_id) thd->insert_id(last_insert_id); // For binary log if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, - table->file->has_transactions(), FALSE); + transactional_table, FALSE); mysql_bin_log.write(&qinfo); } - if (!table->s->tmp_table) - thd->no_trans_update.all= TRUE; + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } - if (info.copied || info.deleted || info.updated) + DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); + if (changed) { query_cache_invalidate3(thd, table, 1); } @@ -3259,7 +3265,6 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE); if (!thd->prelocked_mode) table->file->start_bulk_insert((ha_rows) 0); - thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!info.ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | |