From: Konstantin Osipov Date: July 26 2010 4:13pm Subject: bzr commit into mysql-trunk-runtime branch (kostja:3082) Bug#52044 Bug#55452 List-Archive: http://lists.mysql.com/commits/114363 X-Bug: 52044,55452 Message-Id: <20100726161325.9A6661E6037@ibbur.local> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="Boundary_(ID_Hy+aQU8kVH2LKooryHlAnQ)" --Boundary_(ID_Hy+aQU8kVH2LKooryHlAnQ) MIME-version: 1.0 Content-type: text/plain; CHARSET=US-ASCII Content-transfer-encoding: 7BIT Content-disposition: inline #At file:///opt/local/work/trunk-runtime/ based on revid:jon.hauglid@stripped 3082 Konstantin Osipov 2010-07-26 A pre-requisite patch for the fix for Bug#52044. This patch also fixes Bug#55452 "SET PASSWORD is replicated twice in RBR mode". Cleanup COM_FIELD_LIST. Don't call close_thread_tables() in COM_SHUTDOWN -- there are no open tables there that can be closed (we leave the locked tables mode in THD destructor, and this close_thread_tables() won't leave it anyway). Make open_and_lock_tables() and open_and_lock_tables_derived() call close_thread_tables() upon failure. Remove the calls to close_thread_tables that are now unnecessary. Remove the release of metadata locks from close_thread_tables(). Simplify the back off condition in Open_table_context. Move statement commit outside close_thread_tables(). Streamline metadata lock handling in LOCK TABLES implementation. Add asserts to ensure correct life cycle of statement transaction in a session. @ mysql-test/r/variables.result Update results: set @@autocommit and statement transaction/ prelocked mode. @ mysql-test/r/view.result A harmless change in CHECK TABLE status for a broken view. If previously a failure to prelock all functions used in a view would leave the connection in LTM_PRELOCKED mode, now we call close_thread_tables() from open_and_lock_tables() and leave prelocked mode, thus some check in mysql_admin_table() that works only in prelocked/locked tables mode is no longer activated. @ mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result Fixed Bug#55452 "SET PASSWORD is replicated twice in RBR mode": extra binlog events are gone from the binary log. @ mysql-test/t/variables.test Add a test case: set autocommit and statement transaction/prelocked mode. @ sql/event_data_objects.cc Simplify code in Event_job_data::execute(). Move sp_head memory management to lex_end(). @ sql/event_db_repository.cc Move the release of metadata locks outside close_thread_tables(). Make sure we call close_thread_tables() when open_and_lock_tables() fails and remove extra code from the events data dictionary. Use close_mysql_tables(), a new internal function to properly close mysql.* tables in the data dictionary. Contract Event_db_repository::drop_events_by_field, drop_schema_events into one function. When dropping all events in a schema, make sure we don't mistakenly release all locks acquired by DROP DATABASE. These include locks in the database name and the global shared metadata lock. @ sql/event_db_repository.h Function open_event_table() does not require an instance of Event_db_repository. @ sql/events.cc Use close_mysql_tables() instead of close_thread_tables() to bootstrap events, since the latter no longer releases metadata locks. @ sql/ha_ndbcluster.cc - mysql_rm_table_part2 no longer releases acquired metadata locks. Do it in the caller. @ sql/ha_ndbcluster_binlog.cc Deploy the new protocol for closing thread tables in run_query() and ndb_binlog_index code. @ sql/handler.cc Assert that we never call ha_commit_trans/ ha_rollback_trans in sub-statement, which is now the case. @ sql/handler.h Add an accessor to check whether THD_TRANS object is empty (has no transaction started). @ sql/log.cc Update a comment. @ sql/log_event.cc Since now we commit/rollback statement transaction in mysql_execute_command(), we need a mechanism to communicate from Query_log_event::do_apply_event() to mysql_execute_command() that the statement transaction should be rolled back, not committed. Ideally it would be a virtual method of THD. I hesitate to make THD a virtual base class in this already large patch. Use a thd->variables.option_bits for now. Remove a call to close_thread_tables() from the slave IO thread. It doesn't open any tables, and the protocol for closing thread tables is more complicated now. Make sure we properly close thread tables, however, in Load_data_log_event, which doesn't follow the standard server execution procedure with mysql_execute_command(). @todo: this piece should use Server_runnable framework instead. Remove an unnecessary call to mysql_unlock_tables(). @ sql/rpl_rli.cc Update Relay_log_info::slave_close_thread_tables() to follow the new close protocol. @ sql/set_var.cc Remove an unused header. @ sql/slave.cc Remove an unnecessary call to close_thread_tables(). @ sql/sp.cc Remove unnecessary calls to close_thread_tables() from SP DDL implementation. The tables will be closed by the caller, in mysql_execute_command(). When dropping all routines in a database, make sure to not mistakenly all metadata locks acquired so far, they include the scoped lock on the schema. @ sql/sp_head.cc Correct the protocol that closes thread tables in an SP instruction. Clear lex->sphead before cleaning up lex with lex_end to make sure that we don't delete the sphead twice. It's considered to be "cleaner" and more in line with future changes than calling delete lex->sphead in other places that cleanup the lex. @ sql/sp_head.h When destroying m_lex_keeper of an instruction, don't delete the sphead that all lex objects share. @todo: don't store a reference to routine's sp_head instance in instruction's lex. @ sql/sql_acl.cc Don't call close_thread_tables() where the caller will do that for us. Fix Bug#55452 "SET PASSWORD is replicated twice in RBR mode" by disabling RBR replication in change_password() function. Use close_mysql_tables() in bootstrap and ACL reload code to make sure we release all metadata locks. @ sql/sql_base.cc This is the main part of the patch: - remove manipulation with thd->transaction and thd->mdl_context from close_thread_tables(). Now this function is only responsible for closing tables, nothing else. This is necessary to be able to easily use close_thread_tables() in procedures, that involve multiple open/close tables, which all need to be protected continuously by metadata locks. Add asserts ensuring that TABLE object is only used when is protected by a metadata lock. Simplify the back off condition of Open_table_context, we no longer need to look at the autocommit mode. Make open_and_lock_tables() and open_normal_and_derived_tables() close thread tables and release metadata locks acquired so-far upon failure. This simplifies their usage. Implement close_mysql_tables(). @ sql/sql_base.h Add declaration for close_mysql_tables(). @ sql/sql_do.cc Do nothing in DO if inside a substatement (the assert moved out of trans_rollback_stmt). @ sql/sql_handler.cc Add comments. @ sql/sql_insert.cc Remove dead code. Release metadata locks explicitly at the end of the delayed insert thread. @ sql/sql_lex.cc Add destruction of lex->sphead to lex_end(), lex "reset" method called at the end of each statement. @ sql/sql_parse.cc Move close_thread_tables() and other related cleanups to mysql_execute_command() from dispatch_command(). This has become possible after the fix for Bug#37521. Mark federated SERVER statements as DDL. Next step: make sure that we don't store eof packet in the query cache, and move the query cache code outside mysql_parse. Brush up the code of COM_FIELD_LIST. Remove unnecessary calls to close_thread_tables(). When killing a query, don't report "OK" if it was a suicide. @ sql/sql_parse.h Remove declaration of a function that is now static. @ sql/sql_partition.cc Remove an unnecessary call to close_thread_tables(). @ sql/sql_plugin.cc open_and_lock_tables() will clean up after itself after a failure. Move close_thread_tables() above end: label, and replace with close_mysql_tables(), which will also release the metadata lock on mysql.plugin. @ sql/sql_prepare.cc Now that we no longer release locks in close_thread_tables() statement prepare code has become more straightforward. Remove the now redundant check for thd->killed() (used only by the backup project) from Execute_server_runnable. Reorder code to take into account that now mysql_execute_command() performs lex->unit.cleanup() and close_thread_tables(). @ sql/sql_priv.h Add a new option to server options to interact between the slave SQL thread and execution framework (hack). @todo: use a virtual method of class THD instead. @ sql/sql_servers.cc Due to Bug 25705 replication of DROP/CREATE/ALTER SERVER is broken. Make sure at least we do not attempt to replicate these statements using RBR, as this violates the assert in close_mysql_tables(). @ sql/sql_table.cc Do not release metadata locks in mysql_rm_table_part2, this is done by the caller. Do not call close_thread_tables() in mysql_create_table(), this is done by the caller. Fix a bug in DROP TABLE under LOCK TABLES when, upon error in wait_while_table_is_used() we would mistakenly release the metadata lock on a non-dropped table. Explicitly release metadata locks when doing an implicit commit. @ sql/sql_trigger.cc Now that we delete lex->sphead in lex_end(), zero the trigger's sphead in lex after loading the trigger, to avoid double deletion. @ sql/sql_udf.cc Use close_mysql_tables() instead of close_thread_tables(). @ sql/sys_vars.cc Remove code added in scope of WL#4284 which would break when we perform set @@session.autocommit along with setting other variables and using tables or functions. A test case added to variables.test. @ sql/transaction.cc Add asserts. @ sql/tztime.cc Use close_mysql_tables() rather than close_thread_tables(). modified: mysql-test/r/variables.result mysql-test/r/view.result mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result mysql-test/t/variables.test sql/event_data_objects.cc sql/event_db_repository.cc sql/event_db_repository.h sql/events.cc sql/ha_ndbcluster.cc sql/ha_ndbcluster_binlog.cc sql/handler.cc sql/handler.h sql/log.cc sql/log_event.cc sql/rpl_rli.cc sql/set_var.cc sql/slave.cc sql/sp.cc sql/sp_head.cc sql/sp_head.h sql/sql_acl.cc sql/sql_base.cc sql/sql_base.h sql/sql_class.cc sql/sql_do.cc sql/sql_handler.cc sql/sql_insert.cc sql/sql_lex.cc sql/sql_parse.cc sql/sql_parse.h sql/sql_partition.cc sql/sql_plugin.cc sql/sql_prepare.cc sql/sql_priv.h sql/sql_servers.cc sql/sql_table.cc sql/sql_trigger.cc sql/sql_udf.cc sql/sys_vars.cc sql/transaction.cc sql/tztime.cc === modified file 'mysql-test/r/variables.result' --- a/mysql-test/r/variables.result 2010-06-04 16:09:50 +0000 +++ b/mysql-test/r/variables.result 2010-07-26 16:13:09 +0000 @@ -1677,3 +1677,25 @@ SET @@sql_quote_show_create = @sql_quote # End of Bug#34828. +# Make sure we can manipulate with autocommit in the +# along with other variables. +drop table if exists t1; +drop function if exists t1_max; +drop function if exists t1_min; +create table t1 (a int) engine=innodb; +insert into t1(a) values (0), (1); +create function t1_max() returns int return (select max(a) from t1); +create function t1_min() returns int return (select min(a) from t1); +select t1_min(); +t1_min() +0 +select t1_max(); +t1_max() +1 +set @@session.autocommit=t1_min(), @@session.autocommit=t1_max(), +@@session.autocommit=t1_min(), @@session.autocommit=t1_max(), +@@session.autocommit=t1_min(), @@session.autocommit=t1_max(); +# Cleanup. +drop table t1; +drop function t1_min; +drop function t1_max; === modified file 'mysql-test/r/view.result' --- a/mysql-test/r/view.result 2010-06-06 11:19:29 +0000 +++ b/mysql-test/r/view.result 2010-07-26 16:13:09 +0000 @@ -1955,15 +1955,15 @@ CHECK TABLE v1, v2, v3, v4, v5, v6; Table Op Msg_type Msg_text test.v1 check Error FUNCTION test.f1 does not exist test.v1 check Error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -test.v1 check status Operation failed +test.v1 check error Corrupt test.v2 check status OK test.v3 check Error FUNCTION test.f1 does not exist test.v3 check Error View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -test.v3 check status Operation failed +test.v3 check error Corrupt test.v4 check status OK test.v5 check Error FUNCTION test.f1 does not exist test.v5 check Error View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -test.v5 check status Operation failed +test.v5 check error Corrupt test.v6 check status OK create function f1 () returns int return (select max(col1) from t1); DROP TABLE t1; === modified file 'mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result' --- a/mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result 2010-04-20 09:10:43 +0000 +++ b/mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result 2010-07-26 16:13:09 +0000 @@ -165,10 +165,6 @@ master-bin.000001 # Table_map # # table_ master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; SET PASSWORD FOR 'user'@'localhost'='*D8DECEC305209EEFEC43008E1D420E1AA06B19E0' -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysql.user) -master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> << -b-b-b-b-b-b-b-b-b-b-b- === modified file 'mysql-test/t/variables.test' --- a/mysql-test/t/variables.test 2010-06-04 16:09:50 +0000 +++ b/mysql-test/t/variables.test 2010-07-26 16:13:09 +0000 @@ -1405,4 +1405,30 @@ SET @@sql_quote_show_create = @sql_quote --echo # End of Bug#34828. --echo +--echo # Make sure we can manipulate with autocommit in the +--echo # along with other variables. + + +--disable_warnings +drop table if exists t1; +drop function if exists t1_max; +drop function if exists t1_min; +--enable_warnings + +create table t1 (a int) engine=innodb; +insert into t1(a) values (0), (1); +create function t1_max() returns int return (select max(a) from t1); +create function t1_min() returns int return (select min(a) from t1); +select t1_min(); +select t1_max(); +set @@session.autocommit=t1_min(), @@session.autocommit=t1_max(), + @@session.autocommit=t1_min(), @@session.autocommit=t1_max(), + @@session.autocommit=t1_min(), @@session.autocommit=t1_max(); + +--echo # Cleanup. +drop table t1; +drop function t1_min; +drop function t1_max; + + ########################################################################### === modified file 'sql/event_data_objects.cc' --- a/sql/event_data_objects.cc 2010-07-08 21:20:08 +0000 +++ b/sql/event_data_objects.cc 2010-07-26 16:13:09 +0000 @@ -1402,6 +1402,8 @@ Event_job_data::execute(THD *thd, bool d */ thd->set_db(dbname.str, dbname.length); + lex_start(thd); + #ifndef NO_EMBEDDED_ACCESS_CHECKS if (event_sctx.change_security_context(thd, &definer_user, &definer_host, @@ -1411,7 +1413,7 @@ Event_job_data::execute(THD *thd, bool d "[%s].[%s.%s] execution failed, " "failed to authenticate the user.", definer.str, dbname.str, name.str); - goto end_no_lex_start; + goto end; } #endif @@ -1427,11 +1429,11 @@ Event_job_data::execute(THD *thd, bool d "[%s].[%s.%s] execution failed, " "user no longer has EVENT privilege.", definer.str, dbname.str, name.str); - goto end_no_lex_start; + goto end; } if (construct_sp_sql(thd, &sp_sql)) - goto end_no_lex_start; + goto end; /* Set up global thread attributes to reflect the properties of @@ -1451,8 +1453,6 @@ Event_job_data::execute(THD *thd, bool d if (parser_state.init(thd, thd->query(), thd->query_length())) goto end; - lex_start(thd); - if (parse_sql(thd, & parser_state, creation_ctx)) { sql_print_error("Event Scheduler: " @@ -1484,13 +1484,6 @@ Event_job_data::execute(THD *thd, bool d } end: - if (thd->lex->sphead) /* NULL only if a parse error */ - { - delete thd->lex->sphead; - thd->lex->sphead= NULL; - } - -end_no_lex_start: if (drop && !thd->is_fatal_error) { /* @@ -1529,7 +1522,6 @@ end_no_lex_start: if (save_sctx) event_sctx.restore_security_context(thd, save_sctx); #endif - lex_end(thd->lex); thd->lex->unit.cleanup(); thd->end_statement(); thd->cleanup_after_query(); === modified file 'sql/event_db_repository.cc' --- a/sql/event_db_repository.cc 2010-03-31 14:05:33 +0000 +++ b/sql/event_db_repository.cc 2010-07-26 16:13:09 +0000 @@ -518,17 +518,20 @@ Event_db_repository::table_scan_all_for_ */ bool -Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables, +Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *i_s_table, const char *db) { - TABLE *schema_table= tables->table; - TABLE *event_table= NULL; + TABLE *schema_table= i_s_table->table; + Open_tables_backup open_tables_backup; + TABLE_LIST event_table; int ret= 0; DBUG_ENTER("Event_db_repository::fill_schema_events"); DBUG_PRINT("info",("db=%s", db? db:"(null)")); - if (open_event_table(thd, TL_READ, &event_table)) + event_table.init_one_table("mysql", 5, "event", 5, "event", TL_READ); + + if (open_system_tables_for_read(thd, &event_table, &open_tables_backup)) DBUG_RETURN(TRUE); /* @@ -541,11 +544,11 @@ Event_db_repository::fill_schema_events( every single row's `db` with the schema which we show. */ if (db) - ret= index_read_for_db_for_i_s(thd, schema_table, event_table, db); + ret= index_read_for_db_for_i_s(thd, schema_table, event_table.table, db); else - ret= table_scan_all_for_i_s(thd, schema_table, event_table); + ret= table_scan_all_for_i_s(thd, schema_table, event_table.table); - close_thread_tables(thd); + close_system_tables(thd, &open_tables_backup); DBUG_PRINT("info", ("Return code=%d", ret)); DBUG_RETURN(ret); @@ -584,10 +587,7 @@ Event_db_repository::open_event_table(TH tables.init_one_table("mysql", 5, "event", 5, "event", lock_type); if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - { - close_thread_tables(thd); DBUG_RETURN(TRUE); - } *table= tables.table; tables.table->use_all_columns(); @@ -700,7 +700,8 @@ Event_db_repository::create_event(THD *t end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -811,7 +812,8 @@ Event_db_repository::update_event(THD *t end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -865,7 +867,7 @@ Event_db_repository::drop_event(THD *thd end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); DBUG_RETURN(test(ret)); } @@ -934,33 +936,13 @@ Event_db_repository::find_named_event(LE void Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema) { - DBUG_ENTER("Event_db_repository::drop_schema_events"); - drop_events_by_field(thd, ET_FIELD_DB, schema); - DBUG_VOID_RETURN; -} - - -/** - Drops all events which have a specific value of a field. - - @pre The thread handle has no open tables. - - @param[in,out] thd Thread - @param[in,out] table mysql.event TABLE - @param[in] field Which field of the row to use for matching - @param[in] field_value The value that should match -*/ - -void -Event_db_repository::drop_events_by_field(THD *thd, - enum enum_events_table_field field, - LEX_STRING field_value) -{ int ret= 0; TABLE *table= NULL; READ_RECORD read_record_info; - DBUG_ENTER("Event_db_repository::drop_events_by_field"); - DBUG_PRINT("enter", ("field=%d field_value=%s", field, field_value.str)); + enum enum_events_table_field field= ET_FIELD_DB; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + DBUG_ENTER("Event_db_repository::drop_schema_events"); + DBUG_PRINT("enter", ("field=%d schema=%s", field, schema.str)); if (open_event_table(thd, TL_WRITE, &table)) DBUG_VOID_RETURN; @@ -979,7 +961,7 @@ Event_db_repository::drop_events_by_fiel get_field(thd->mem_root, table->field[ET_FIELD_NAME]))); - if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info)) + if (!sortcmp_lex_string(et_field_lex, schema, system_charset_info)) { DBUG_PRINT("info", ("Dropping")); if ((ret= table->file->ha_delete_row(table->record[0]))) @@ -989,6 +971,11 @@ Event_db_repository::drop_events_by_fiel } end_read_record(&read_record_info); close_thread_tables(thd); + /* + Make sure to only release the MDL lock on mysql.event, not other + metadata locks DROP DATABASE might have acquired. + */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); DBUG_VOID_RETURN; } @@ -1026,7 +1013,7 @@ Event_db_repository::load_named_event(TH else if ((ret= etn->load_from_row(thd, table))) my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event"); - close_thread_tables(thd); + close_mysql_tables(thd); } thd->variables.sql_mode= saved_mode; @@ -1104,7 +1091,8 @@ update_timing_fields_for_event(THD *thd, end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); + /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1151,7 +1139,7 @@ Event_db_repository::check_system_tables if (table_intact.check(tables.table, &mysql_db_table_def)) ret= 1; - close_thread_tables(thd); + close_mysql_tables(thd); } /* Check mysql.user */ tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ); @@ -1171,7 +1159,7 @@ Event_db_repository::check_system_tables event_priv_column_position); ret= 1; } - close_thread_tables(thd); + close_mysql_tables(thd); } /* Check mysql.event */ tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ); @@ -1185,7 +1173,7 @@ Event_db_repository::check_system_tables { if (table_intact.check(tables.table, &event_table_def)) ret= 1; - close_thread_tables(thd); + close_mysql_tables(thd); } DBUG_RETURN(test(ret)); === modified file 'sql/event_db_repository.h' --- a/sql/event_db_repository.h 2007-08-15 15:08:44 +0000 +++ b/sql/event_db_repository.h 2010-07-26 16:13:09 +0000 @@ -91,7 +91,7 @@ public: bool load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et); - bool + static bool open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table); bool @@ -109,9 +109,6 @@ public: static bool check_system_tables(THD *thd); private: - void - drop_events_by_field(THD *thd, enum enum_events_table_field field, - LEX_STRING field_value); bool index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table, const char *db); === modified file 'sql/events.cc' --- a/sql/events.cc 2010-04-19 12:09:44 +0000 +++ b/sql/events.cc 2010-07-26 16:13:09 +0000 @@ -16,7 +16,7 @@ #include "sql_priv.h" #include "unireg.h" #include "sql_parse.h" // check_access -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "sql_show.h" // append_definer #include "events.h" #include "sql_db.h" // check_db_dir_existence @@ -754,7 +754,6 @@ Events::fill_schema_events(THD *thd, TAB { char *db= NULL; int ret; - Open_tables_backup open_tables_backup; DBUG_ENTER("Events::fill_schema_events"); if (check_if_system_tables_error()) @@ -773,15 +772,7 @@ Events::fill_schema_events(THD *thd, TAB DBUG_RETURN(1); db= thd->lex->select_lex.db; } - /* - Reset and backup of the currently open tables in this thread - is a way to allow SELECTs from INFORMATION_SCHEMA.events under - LOCK TABLES and in pre-locked mode. See also - Events::show_create_event for additional comments. - */ - thd->reset_n_backup_open_tables_state(&open_tables_backup); ret= db_repository->fill_schema_events(thd, tables, db); - thd->restore_backup_open_tables_state(&open_tables_backup); DBUG_RETURN(ret); } @@ -1161,8 +1152,7 @@ Events::load_events_from_db(THD *thd) end: end_read_record(&read_record_info); - close_thread_tables(thd); - + close_mysql_tables(thd); DBUG_RETURN(ret); } === modified file 'sql/ha_ndbcluster.cc' --- a/sql/ha_ndbcluster.cc 2010-07-08 21:20:08 +0000 +++ b/sql/ha_ndbcluster.cc 2010-07-26 16:13:09 +0000 @@ -7417,7 +7417,8 @@ int ndbcluster_find_files(handlerton *ht FALSE, /* drop_temporary */ FALSE, /* drop_view */ TRUE /* dont_log_query*/); - + trans_commit_implicit(thd); /* Safety, should be unnecessary. */ + thd->mdl_context.release_transactional_locks(); /* Clear error message that is returned when table is deleted */ thd->clear_error(); } === modified file 'sql/ha_ndbcluster_binlog.cc' --- a/sql/ha_ndbcluster_binlog.cc 2010-07-08 21:20:08 +0000 +++ b/sql/ha_ndbcluster_binlog.cc 2010-07-26 16:13:09 +0000 @@ -298,13 +298,6 @@ static void run_query(THD *thd, char *bu thd_ndb->m_error_code, (int) thd->is_error(), thd->is_slave_error); } - - /* - After executing statement we should unlock and close tables open - by it as well as release meta-data locks obtained by it. - */ - close_thread_tables(thd); - /* XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command() can not be called from within a statement, and @@ -2422,7 +2415,11 @@ int ndb_add_ndb_binlog_index(THD *thd, v } add_ndb_binlog_index_err: + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; thd->variables.option_bits= saved_options; return error; @@ -3969,7 +3966,9 @@ restart: { if (ndb_binlog_index->s->needs_reopen()) { + trans_commit_stmt(thd); close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; } } @@ -4280,7 +4279,9 @@ restart: if (do_ndbcluster_binlog_close_connection == BCCC_restart) { ndb_binlog_tables_inited= FALSE; + trans_commit_stmt(thd); close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; goto restart; } @@ -4288,7 +4289,11 @@ err: sql_print_information("Stopping Cluster Binlog"); DBUG_PRINT("info",("Shutting down cluster binlog thread")); thd->proc_info= "Shutting down"; + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); mysql_mutex_lock(&injector_mutex); /* don't mess with the injector_ndb anymore from other threads */ injector_thd= 0; === modified file 'sql/handler.cc' --- a/sql/handler.cc 2010-07-08 21:20:08 +0000 +++ b/sql/handler.cc 2010-07-26 16:13:09 +0000 @@ -976,6 +976,8 @@ void trans_register_ha(THD *thd, bool al DBUG_ENTER("trans_register_ha"); DBUG_PRINT("enter",("%s", all ? "all" : "stmt")); + /* We don't do transactions when working with system tables. */ + DBUG_ASSERT(! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); if (all) { trans= &thd->transaction.all; @@ -1145,6 +1147,7 @@ int ha_commit_trans(THD *thd, bool all) if (thd->in_sub_stmt) { + DBUG_ASSERT(0); /* Since we don't support nested statement transactions in 5.0, we can't commit or rollback stmt transactions while we are inside @@ -1159,7 +1162,6 @@ int ha_commit_trans(THD *thd, bool all) bail out with error even before ha_commit_trans() call. To be 100% safe let us throw error in non-debug builds. */ - DBUG_ASSERT(0); my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); DBUG_RETURN(2); } @@ -1342,6 +1344,7 @@ int ha_rollback_trans(THD *thd, bool all if (thd->in_sub_stmt) { + DBUG_ASSERT(0); /* If we are inside stored function or trigger we should not commit or rollback current statement transaction. See comment in ha_commit_trans() @@ -1349,7 +1352,6 @@ int ha_rollback_trans(THD *thd, bool all */ if (!all) DBUG_RETURN(0); - DBUG_ASSERT(0); my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); DBUG_RETURN(1); } === modified file 'sql/handler.h' --- a/sql/handler.h 2010-07-15 13:47:50 +0000 +++ b/sql/handler.h 2010-07-26 16:13:09 +0000 @@ -846,6 +846,7 @@ struct THD_TRANS bool modified_non_trans_table; void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; } + bool is_empty() const { return ha_list == NULL; } }; === modified file 'sql/log.cc' --- a/sql/log.cc 2010-07-15 13:47:50 +0000 +++ b/sql/log.cc 2010-07-26 16:13:09 +0000 @@ -27,7 +27,7 @@ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "log.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // open_log_table #include "sql_repl.h" #include "sql_delete.h" // mysql_truncate #include "sql_parse.h" // command_name === modified file 'sql/log_event.cc' --- a/sql/log_event.cc 2010-07-15 13:47:50 +0000 +++ b/sql/log_event.cc 2010-07-26 16:13:09 +0000 @@ -3332,6 +3332,19 @@ int Query_log_event::do_apply_event(Rela thd->table_map_for_update= (table_map)table_map_for_update; thd->set_invoker(&user, &host); + /* + Flag if we need to rollback the statement transaction on + slave if it by chance succeeds. + If we expected a non-zero error code and get nothing and, + it is a concurrency issue or ignorable issue, effects + of the statement should be rolled back. + */ + if (expected_error && + (ignored_error_code(expected_error) || + concurrency_error_code(expected_error))) + { + thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR; + } /* Execute the query (note that we bypass dispatch_command()) */ Parser_state parser_state; if (!parser_state.init(thd, thd->query(), thd->query_length())) @@ -3340,6 +3353,8 @@ int Query_log_event::do_apply_event(Rela log_slow_statement(thd); } + thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR; + /* Resetting the enable_slow_log thd variable. @@ -3382,7 +3397,6 @@ START SLAVE; . Query: '%s'", expected_er general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); compare_errors: - /* In the slave thread, we may sometimes execute some DROP / * 40005 TEMPORARY * / TABLE that come from parts of binlogs (likely if we @@ -3430,26 +3444,8 @@ Default database: '%s'. Query: '%s'", DBUG_PRINT("info",("error ignored")); clear_all_errors(thd, const_cast(rli)); thd->killed= THD::NOT_KILLED; - /* - When an error is expected and matches the actual error the - slave does not report any error and by consequence changes - on transactional tables are not rolled back in the function - close_thread_tables(). For that reason, we explicitly roll - them back here. - */ - if (expected_error && expected_error == actual_error) - trans_rollback_stmt(thd); } /* - If we expected a non-zero error code and get nothing and, it is a concurrency - issue or should be ignored. - */ - else if (expected_error && !actual_error && - (concurrency_error_code(expected_error) || - ignored_error_code(expected_error))) - trans_rollback_stmt(thd); - - /* Other cases: mostly we expected no error and get one. */ else if (thd->is_slave_error || thd->is_fatal_error) @@ -3516,7 +3512,6 @@ end: thd->set_db(NULL, 0); /* will free the current database */ thd->set_query(NULL, 0); DBUG_PRINT("info", ("end: query= 0")); - close_thread_tables(thd); /* As a disk space optimization, future masters will not log an event for LAST_INSERT_ID() if that function returned 0 (and thus they will be able @@ -4946,7 +4941,22 @@ error: thd->catalog= 0; thd->set_db(NULL, 0); /* will free the current database */ thd->set_query(NULL, 0); + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + /* + - If inside a multi-statement transaction, + defer the release of metadata locks until the current + transaction is either committed or rolled back. This prevents + other statements from modifying the table for the entire + duration of this transaction. This provides commit ordering + and guarantees serializability across multiple transactions. + - If in autocommit mode, or outside a transactional context, + automatically release metadata locks of the current statement. + */ + if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", thd->is_slave_error= 0; thd->is_fatal_error= 1;); @@ -5531,11 +5541,9 @@ int Xid_log_event::do_apply_event(Relay_ /* For a slave Xid_log_event is COMMIT */ general_log_print(thd, COM_QUERY, "COMMIT /* implicit, from Xid_log_event */"); - if (!(res= trans_commit(thd))) - { - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); - } + res= trans_commit(thd); /* Automatically rolls back on error. */ + thd->mdl_context.release_transactional_locks(); + return res; } @@ -7610,8 +7618,6 @@ int Rows_log_event::do_apply_event(Relay We should not honour --slave-skip-errors at this point as we are having severe errors which should not be skiped. */ - mysql_unlock_tables(thd, thd->lock); - thd->lock= 0; thd->is_slave_error= 1; const_cast(rli)->slave_close_thread_tables(thd); DBUG_RETURN(ERR_BAD_TABLE_DEF); === modified file 'sql/rpl_rli.cc' --- a/sql/rpl_rli.cc 2010-07-15 13:47:50 +0000 +++ b/sql/rpl_rli.cc 2010-07-26 16:13:09 +0000 @@ -1257,7 +1257,23 @@ void Relay_log_info::clear_tables_to_loc void Relay_log_info::slave_close_thread_tables(THD *thd) { + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + close_thread_tables(thd); + /* + - If inside a multi-statement transaction, + defer the release of metadata locks until the current + transaction is either committed or rolled back. This prevents + other statements from modifying the table for the entire + duration of this transaction. This provides commit ordering + and guarantees serializability across multiple transactions. + - If in autocommit mode, or outside a transactional context, + automatically release metadata locks of the current statement. + */ + if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); clear_tables_to_lock(); } #endif === modified file 'sql/set_var.cc' --- a/sql/set_var.cc 2010-07-02 19:38:04 +0000 +++ b/sql/set_var.cc 2010-07-26 16:13:09 +0000 @@ -27,7 +27,6 @@ #include "mysqld.h" // lc_messages_dir #include "sys_vars_shared.h" #include "transaction.h" -#include "sql_base.h" // close_thread_tables #include "sql_locale.h" // my_locale_by_number, // my_locale_by_name #include "strfunc.h" // find_set_from_flags, find_set === modified file 'sql/slave.cc' --- a/sql/slave.cc 2010-07-15 13:47:50 +0000 +++ b/sql/slave.cc 2010-07-26 16:13:09 +0000 @@ -3044,7 +3044,6 @@ err: change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE); DBUG_ASSERT(thd->net.buff != 0); net_end(&thd->net); // destructor will not free it, because net.vio is 0 - close_thread_tables(thd); mysql_mutex_lock(&LOCK_thread_count); THD_CHECK_SENTRY(thd); delete thd; === modified file 'sql/sp.cc' --- a/sql/sp.cc 2010-06-11 13:54:39 +0000 +++ b/sql/sp.cc 2010-07-26 16:13:09 +0000 @@ -450,10 +450,7 @@ static TABLE *open_proc_table_for_update if (!proc_table_intact.check(table, &proc_table_def)) DBUG_RETURN(table); - close_thread_tables(thd); - DBUG_RETURN(NULL); - } @@ -856,6 +853,7 @@ db_load_routine(THD *thd, int type, sp_n } end: + thd->lex->sphead= NULL; lex_end(thd->lex); thd->lex= old_lex; return ret; @@ -1159,8 +1157,6 @@ sp_create_routine(THD *thd, int type, sp done: thd->count_cuted_fields= saved_count_cuted_fields; thd->variables.sql_mode= saved_mode; - - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1239,8 +1235,6 @@ sp_drop_routine(THD *thd, int type, sp_n sp_cache_flush_obsolete(spc, &sp); } } - - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1348,7 +1342,6 @@ sp_update_routine(THD *thd, int type, sp sp_cache_invalidate(); } err: - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1370,6 +1363,7 @@ sp_drop_db_routines(THD *thd, char *db) TABLE *table; int ret; uint key_len; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("sp_drop_db_routines"); DBUG_PRINT("enter", ("db: %s", db)); @@ -1410,6 +1404,11 @@ sp_drop_db_routines(THD *thd, char *db) table->file->ha_index_end(); close_thread_tables(thd); + /* + Make sure to only release the MDL lock on mysql.proc, not other + metadata locks DROP DATABASE might have acquired. + */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); err: DBUG_RETURN(ret); @@ -2142,6 +2141,7 @@ sp_load_for_information_schema(THD *thd, newlex.current_select= NULL; sp= sp_compile(thd, &defstr, sql_mode, creation_ctx); *free_sp_head= 1; + thd->lex->sphead= NULL; lex_end(thd->lex); thd->lex= old_lex; return sp; === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2010-06-17 13:31:51 +0000 +++ b/sql/sp_head.cc 2010-07-26 16:13:09 +0000 @@ -38,6 +38,7 @@ #include "set_var.h" #include "sql_parse.h" // cleanup_items #include "sql_base.h" // close_thread_tables +#include "transaction.h" // trans_commit_stmt /* Sufficient max length of printed destinations and frame offsets (all uints). @@ -795,6 +796,7 @@ sp_head::~sp_head() while ((lex= (LEX *)m_lex.pop())) { THD *thd= lex->thd; + thd->lex->sphead= NULL; lex_end(thd->lex); delete thd->lex; thd->lex= lex; @@ -1995,16 +1997,23 @@ sp_head::execute_procedure(THD *thd, Lis arguments evaluation. If arguments evaluation required prelocking mode, we'll leave it here. */ + thd->lex->unit.cleanup(); + if (!thd->in_sub_stmt) { - thd->lex->unit.cleanup(); + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + } - thd_proc_info(thd, "closing tables"); - close_thread_tables(thd); - thd_proc_info(thd, 0); + thd_proc_info(thd, "closing tables"); + close_thread_tables(thd); + thd_proc_info(thd, 0); - thd->rollback_item_tree_changes(); - } + if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + + thd->rollback_item_tree_changes(); DBUG_PRINT("info",(" %.*s: eval args done", (int) m_name.length, m_name.str)); @@ -2197,6 +2206,7 @@ sp_head::restore_lex(THD *thd) merge_table_list(thd, sublex->query_tables, sublex); if (! sublex->sp_lex_in_use) { + sublex->sphead= NULL; lex_end(sublex); delete sublex; } @@ -2806,12 +2816,27 @@ sp_lex_keeper::reset_lex_and_exec_core(T DBUG_PRINT("info",("exec_core returned: %d", res)); } - m_lex->unit.cleanup(); + /* + Call after unit->cleanup() to close open table + key read. + */ + if (open_tables) + { + m_lex->unit.cleanup(); + /* Here we also commit or rollback the current statement. */ + if (! thd->in_sub_stmt) + { + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + } + thd_proc_info(thd, "closing tables"); + close_thread_tables(thd); + thd_proc_info(thd, 0); - thd_proc_info(thd, "closing tables"); - /* Here we also commit or rollback the current statement. */ - close_thread_tables(thd); - thd_proc_info(thd, 0); + if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + } if (m_lex->query_tables_own_last) { === modified file 'sql/sp_head.h' --- a/sql/sp_head.h 2010-06-06 11:19:29 +0000 +++ b/sql/sp_head.h 2010-07-26 16:13:09 +0000 @@ -682,6 +682,8 @@ public: { if (m_lex_resp) { + /* Prevent endless recursion. */ + m_lex->sphead= NULL; lex_end(m_lex); delete m_lex; } === modified file 'sql/sql_acl.cc' --- a/sql/sql_acl.cc 2010-07-19 08:27:53 +0000 +++ b/sql/sql_acl.cc 2010-07-26 16:13:09 +0000 @@ -27,7 +27,7 @@ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_acl.h" // MYSQL_DB_FIELD_COUNT, ACL_ACCESS -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "key.h" // key_copy, key_cmp_if_same, key_restore #include "sql_show.h" // append_identifier #include "sql_table.h" // build_table_filename @@ -730,9 +730,7 @@ my_bool acl_reload(THD *thd) if (old_initialized) mysql_mutex_unlock(&acl_cache->lock); end: - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); DBUG_RETURN(return_val); } @@ -1585,6 +1583,7 @@ bool change_password(THD *thd, const cha /* Buffer should be extended when password length is extended. */ char buff[512]; ulong query_length; + bool save_binlog_row_based; uint new_password_len= (uint) strlen(new_password); bool result= 1; DBUG_ENTER("change_password"); @@ -1614,10 +1613,17 @@ bool change_password(THD *thd, const cha DBUG_RETURN(0); } #endif - if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(1); + /* + This statement will be replicated as a statement, even when using + row-based replication. The flag will be reset at the end of the + statement. + */ + if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row())) + thd->clear_current_stmt_binlog_format_row(); + mysql_mutex_lock(&acl_cache->lock); ACL_USER *acl_user; if (!(acl_user= find_acl_user(host, user, TRUE))) @@ -1652,7 +1658,13 @@ bool change_password(THD *thd, const cha FALSE, FALSE, FALSE, 0); } end: - close_thread_tables(thd); + close_mysql_tables(thd); + + /* Restore the state of binlog format */ + DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); + if (save_binlog_row_based) + thd->set_current_stmt_binlog_format_row(); + DBUG_RETURN(result); } @@ -3082,7 +3094,7 @@ int mysql_table_grant(THD *thd, TABLE_LI DBUG_RETURN(TRUE); column_priv|= column->rights; } - close_thread_tables(thd); + close_mysql_tables(thd); } else { @@ -3172,7 +3184,6 @@ int mysql_table_grant(THD *thd, TABLE_LI thd->lex->sql_command= backup.sql_command; if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen - close_thread_tables(thd); /* purecov: deadcode */ /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -3398,7 +3409,6 @@ bool mysql_routine_grant(THD *thd, TABLE if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -3553,7 +3563,6 @@ bool mysql_grant(THD *thd, const char *d if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen - close_thread_tables(thd); /* purecov: deadcode */ /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -3613,7 +3622,6 @@ bool mysql_grant(THD *thd, const char *d } mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); if (!result) my_ok(thd); @@ -3874,10 +3882,7 @@ static my_bool grant_reload_procs_priv(T table.open_type= OT_BASE_ONLY; if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - { - close_thread_tables(thd); DBUG_RETURN(TRUE); - } mysql_rwlock_wrlock(&LOCK_grant); /* Save a copy of the current hash if we need to undo the grant load */ @@ -3899,7 +3904,7 @@ static my_bool grant_reload_procs_priv(T } mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); + close_mysql_tables(thd); DBUG_RETURN(return_val); } @@ -3970,9 +3975,7 @@ my_bool grant_reload(THD *thd) free_root(&old_mem,MYF(0)); } mysql_rwlock_unlock(&LOCK_grant); - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); /* It is OK failing to load procs_priv table because we may be @@ -5250,7 +5253,6 @@ int open_grant_tables(THD *thd, TABLE_LI if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen - close_thread_tables(thd); DBUG_RETURN(-1); } @@ -5890,7 +5892,6 @@ bool mysql_create_user(THD *thd, List query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -5975,7 +5976,6 @@ bool mysql_drop_user(THD *thd, List query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); thd->variables.sql_mode= old_sql_mode; /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); @@ -6072,7 +6072,6 @@ bool mysql_rename_user(THD *thd, List query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -6270,8 +6269,6 @@ bool mysql_revoke_all(THD *thd, List query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); - /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -6418,7 +6415,6 @@ bool sp_revoke_privileges(THD *thd, cons mysql_mutex_unlock(&acl_cache->lock); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); thd->pop_internal_handler(); /* Restore the state of binlog format */ === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2010-07-19 08:27:53 +0000 +++ b/sql/sql_base.cc 2010-07-26 16:13:09 +0000 @@ -1402,6 +1402,9 @@ void close_thread_tables(THD *thd) DEBUG_SYNC(thd, "before_close_thread_tables"); #endif + DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt || + (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); + /* Detach MERGE children after every statement. Even under LOCK TABLES. */ for (table= thd->open_tables; table; table= table->next) { @@ -1446,28 +1449,6 @@ void close_thread_tables(THD *thd) Mark all temporary tables used by this statement as free for reuse. */ mark_temp_tables_as_free_for_reuse(thd); - /* - Let us commit transaction for statement. Since in 5.0 we only have - one statement transaction and don't allow several nested statement - transactions this call will do nothing if we are inside of stored - function or trigger (i.e. statement transaction is already active and - does not belong to statement for which we do close_thread_tables()). - TODO: This should be fixed in later releases. - */ - if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) - { - thd->stmt_da->can_overwrite_status= TRUE; - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); - thd->stmt_da->can_overwrite_status= FALSE; - - /* - Reset transaction state, but only if we're not inside a - sub-statement of a prelocked statement. - */ - if (thd->locked_tables_mode <= LTM_LOCK_TABLES || - thd->lex->requires_prelocking()) - thd->transaction.stmt.reset(); - } if (thd->locked_tables_mode) { @@ -1528,26 +1509,6 @@ void close_thread_tables(THD *thd) if (thd->open_tables) close_open_tables(thd); - /* - - If inside a multi-statement transaction, - defer the release of metadata locks until the current - transaction is either committed or rolled back. This prevents - other statements from modifying the table for the entire - duration of this transaction. This provides commit ordering - and guarantees serializability across multiple transactions. - - If closing a system table, defer the release of metadata locks - to the caller. We have no sentinel in MDL subsystem to guard - transactional locks from system tables locks, so don't know - which locks are which here. - - If in autocommit mode, or outside a transactional context, - automatically release metadata locks of the current statement. - */ - if (! thd->in_multi_stmt_transaction_mode() && - ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) - { - thd->mdl_context.release_transactional_locks(); - } - DBUG_VOID_RETURN; } @@ -1562,7 +1523,14 @@ bool close_thread_table(THD *thd, TABLE DBUG_ASSERT(table->key_read == 0); DBUG_ASSERT(!table->file || table->file->inited == handler::NONE); mysql_mutex_assert_not_owner(&LOCK_open); - + /* + The metadata lock must be released after giving back + the table to the table cache. + */ + DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, + table->s->db.str, + table->s->table_name.str, + MDL_SHARED)); table->mdl_ticket= NULL; mysql_mutex_lock(&thd->LOCK_thd_data); @@ -3188,6 +3156,7 @@ Locked_tables_list::init_locked_tables(T return FALSE; } + /** Leave LTM_LOCK_TABLES mode if it's been entered. @@ -3224,7 +3193,12 @@ Locked_tables_list::unlock_locked_tables } thd->leave_locked_tables_mode(); + DBUG_ASSERT(thd->transaction.stmt.is_empty()); close_thread_tables(thd); + /* + We rely on the caller to implicitly commit the + transaction and release transactional locks. + */ } /* After closing tables we can free memory used for storing lock @@ -3810,9 +3784,7 @@ Open_table_context::Open_table_context(T LONG_TIMEOUT : thd->variables.lock_wait_timeout), m_flags(flags), m_action(OT_NO_ACTION), - m_has_locks((thd->in_multi_stmt_transaction_mode() && - thd->mdl_context.has_locks()) || - thd->mdl_context.trans_sentinel()) + m_has_locks(thd->mdl_context.has_locks()) {} @@ -5264,6 +5236,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST table= 0; end: + if (error) + close_thread_tables(thd); thd_proc_info(thd, 0); DBUG_RETURN(table); } @@ -5282,7 +5256,8 @@ end: should work for this statement. @note - The lock will automaticaly be freed by close_thread_tables() + The thr_lock locks will automatically be freed by + close_thread_tables(). @retval FALSE OK. @retval TRUE Error @@ -5293,11 +5268,12 @@ bool open_and_lock_tables(THD *thd, TABL Prelocking_strategy *prelocking_strategy) { uint counter; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_and_lock_tables"); DBUG_PRINT("enter", ("derived handling: %d", derived)); if (open_tables(thd, &tables, &counter, flags, prelocking_strategy)) - DBUG_RETURN(TRUE); + goto err; DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", { const char *old_proc_info= thd->proc_info; @@ -5306,15 +5282,22 @@ bool open_and_lock_tables(THD *thd, TABL thd->proc_info= old_proc_info;}); if (lock_tables(thd, tables, counter, flags)) - DBUG_RETURN(TRUE); + goto err; if (derived && (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || (thd->fill_derived_tables() && mysql_handle_derived(thd->lex, &mysql_derived_filling)))) - DBUG_RETURN(TRUE); /* purecov: inspected */ + goto err; DBUG_RETURN(FALSE); +err: + if (! thd->in_sub_stmt) + trans_rollback_stmt(thd); /* Necessary if derived handling failed. */ + close_thread_tables(thd); + /* Don't keep locks for a failed statement. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + DBUG_RETURN(TRUE); } @@ -5340,13 +5323,24 @@ bool open_and_lock_tables(THD *thd, TABL bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags) { + DML_prelocking_strategy prelocking_strategy; uint counter; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_normal_and_derived_tables"); DBUG_ASSERT(!thd->fill_derived_tables()); - if (open_tables(thd, &tables, &counter, flags) || + if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) || mysql_handle_derived(thd->lex, &mysql_derived_prepare)) - DBUG_RETURN(TRUE); /* purecov: inspected */ + goto end; + DBUG_RETURN(0); +end: + /* No need to rollback statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + /* Don't keep locks for a failed statement. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + + DBUG_RETURN(TRUE); /* purecov: inspected */ } @@ -5607,6 +5601,14 @@ void close_tables_for_reopen(THD *thd, T /* We have to cleanup translation tables of views. */ tmp->cleanup_items(); } + /* + No need to commit/rollback the statement transaction: it's + either not started or we're filling in an INFORMATION_SCHEMA + table on the fly, and thus mustn't manipulate with the + transaction of the enclosing statement. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty() || + (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); close_thread_tables(thd); thd->mdl_context.rollback_to_savepoint(start_of_statement_svp); } @@ -9034,7 +9036,8 @@ open_system_tables_for_read(THD *thd, TA MYSQL_LOCK_IGNORE_TIMEOUT)) { lex->restore_backup_query_tables_list(&query_tables_list_backup); - goto error; + thd->restore_backup_open_tables_state(backup); + DBUG_RETURN(TRUE); } for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global) @@ -9045,11 +9048,6 @@ open_system_tables_for_read(THD *thd, TA lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(FALSE); - -error: - close_system_tables(thd, backup); - - DBUG_RETURN(TRUE); } @@ -9072,6 +9070,38 @@ close_system_tables(THD *thd, Open_table } +/** + A helper function to close a mysql.* table opened + in an auxiliary THD during bootstrap or in the main + connection, when we know that there are no locks + held by the connection due to a preceding implicit + commit. + + This function assumes that there is no + statement transaction started for the operation + itself, since mysql.* tables are not transactional + and when they are used the binlog is off (DDL + binlogging is always statement-based. + + We need this function since we'd like to not + just close the system table, but also release + the metadata lock on it. + + Note, that in LOCK TABLES mode this function + does not release the metadata lock. But in this + mode the table can be opened only if it is locked + explicitly with LOCK TABLES. +*/ + +void +close_mysql_tables(THD *thd) +{ + /* No need to commit/rollback statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); +} + /* Open and lock one system table for update. @@ -9143,16 +9173,7 @@ open_log_table(THD *thd, TABLE_LIST *one table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; } else - { - /* - If error in mysql_lock_tables(), open_ltable doesn't close the - table. Thread kill during mysql_lock_tables() is such error. But - open tables cannot be accepted when restoring the open tables - state. - */ - close_thread_tables(thd); thd->restore_backup_open_tables_state(backup); - } thd->utime_after_lock= save_utime_after_lock; DBUG_RETURN(table); === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2010-07-01 14:58:47 +0000 +++ b/sql/sql_base.h 2010-07-26 16:13:09 +0000 @@ -240,6 +240,7 @@ bool is_equal(const LEX_STRING *a, const bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, Open_tables_backup *backup); void close_system_tables(THD *thd, Open_tables_backup *backup); +void close_mysql_tables(THD *thd); TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table); TABLE *open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup); void close_log_table(THD *thd, Open_tables_backup *backup); === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2010-07-15 13:47:50 +0000 +++ b/sql/sql_class.cc 2010-07-26 16:13:09 +0000 @@ -29,7 +29,6 @@ #include "sql_priv.h" #include "unireg.h" // REQUIRED: for other includes #include "sql_class.h" -#include "lock.h" // unlock_global_read_lock, mysql_unlock_tables #include "sql_cache.h" // query_cache_abort #include "sql_base.h" // close_thread_tables #include "sql_time.h" // date_time_format_copy @@ -1817,12 +1816,6 @@ bool select_send::send_eof() */ ha_release_temporary_latches(thd); - /* Unlock tables before sending packet to gain some speed */ - if (thd->lock && ! thd->locked_tables_mode) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; - } /* Don't send EOF if we're in error condition (which implies we've already sent or are sending an error) === modified file 'sql/sql_do.cc' --- a/sql/sql_do.cc 2010-03-31 14:05:33 +0000 +++ b/sql/sql_do.cc 2010-07-26 16:13:09 +0000 @@ -39,9 +39,10 @@ bool mysql_do(THD *thd, List &valu /* Rollback the effect of the statement, since next instruction will clear the error and the rollback in the end of - dispatch_command() won't work. + mysql_execute_command() won't work. */ - trans_rollback_stmt(thd); + if (! thd->in_sub_stmt) + trans_rollback_stmt(thd); thd->clear_error(); // DO always is OK } my_ok(thd); === modified file 'sql/sql_handler.cc' --- a/sql/sql_handler.cc 2010-07-13 08:39:24 +0000 +++ b/sql/sql_handler.cc 2010-07-26 16:13:09 +0000 @@ -59,7 +59,7 @@ #include "key.h" // key_copy #include "sql_base.h" // insert_fields #include "sql_select.h" -#include +#include "transaction.h" #define HANDLER_TABLES_HASH_SIZE 120 @@ -309,9 +309,15 @@ bool mysql_ha_open(THD *thd, TABLE_LIST } if (error) { + /* + No need to rollback statement transaction, it's not started. + If called with reopen flag, no need to rollback either, + it will be done at statement end. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); close_thread_tables(thd); - thd->set_open_tables(backup_open_tables); thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + thd->set_open_tables(backup_open_tables); if (!reopen) my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables); else @@ -578,6 +584,11 @@ retry: if (sql_handler_lock_error.need_reopen()) { DBUG_ASSERT(!lock && !thd->is_error()); + /* + Always close statement transaction explicitly, + so that the engine doesn't have to count locks. + */ + trans_rollback_stmt(thd); mysql_ha_close_table(thd, hash_tables); goto retry; } @@ -764,12 +775,18 @@ retry: num_rows++; } ok: + /* + Always close statement transaction explicitly, + so that the engine doesn't have to count locks. + */ + trans_commit_stmt(thd); mysql_unlock_tables(thd,lock); my_eof(thd); DBUG_PRINT("exit",("OK")); DBUG_RETURN(FALSE); err: + trans_rollback_stmt(thd); mysql_unlock_tables(thd,lock); err0: DBUG_PRINT("exit",("ERROR")); === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2010-07-08 21:20:08 +0000 +++ b/sql/sql_insert.cc 2010-07-26 16:13:09 +0000 @@ -1862,7 +1862,10 @@ public: while ((row=rows.get())) delete row; if (table) + { close_thread_tables(&thd); + thd.mdl_context.release_transactional_locks(); + } mysql_mutex_lock(&LOCK_thread_count); mysql_mutex_destroy(&mutex); mysql_cond_destroy(&cond); @@ -2619,28 +2622,11 @@ pthread_handler_t handle_delayed_insert( } err: - /* - mysql_lock_tables() can potentially start a transaction and write - a table map. In the event of an error, that transaction has to be - rolled back. We only need to roll back a potential statement - transaction, since real transactions are rolled back in - close_thread_tables(). - - TODO: This is not true any more, table maps are generated on the - first call to ha_*_row() instead. Remove code that are used to - cover for the case outlined above. - */ - trans_rollback_stmt(thd); - DBUG_LEAVE; } - /* - di should be unlinked from the thread handler list and have no active - clients - */ - close_thread_tables(thd); // Free the table + thd->mdl_context.release_transactional_locks(); di->table=0; thd->killed= THD::KILL_CONNECTION; // If error mysql_cond_broadcast(&di->cond_client); // Safety @@ -2648,6 +2634,10 @@ pthread_handler_t handle_delayed_insert( mysql_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table mysql_mutex_lock(&LOCK_delayed_insert); + /* + di should be unlinked from the thread handler list and have no active + clients + */ delete di; mysql_mutex_unlock(&LOCK_delayed_insert); mysql_mutex_unlock(&LOCK_delayed_create); === modified file 'sql/sql_lex.cc' --- a/sql/sql_lex.cc 2010-07-08 21:20:08 +0000 +++ b/sql/sql_lex.cc 2010-07-26 16:13:09 +0000 @@ -450,6 +450,9 @@ void lex_end(LEX *lex) } reset_dynamic(&lex->plugins); + delete lex->sphead; + lex->sphead= NULL; + DBUG_VOID_RETURN; } === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2010-07-19 08:27:53 +0000 +++ b/sql/sql_parse.cc 2010-07-26 16:13:09 +0000 @@ -115,6 +115,7 @@ "FUNCTION" : "PROCEDURE") static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); +static void sql_kill(THD *thd, ulong id, bool only_kill_query); const char *any_db="*any*"; // Special symbol for check_access @@ -413,6 +414,9 @@ void init_update_queries(void) sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS; } bool sqlcom_can_generate_row_events(const THD *thd) @@ -568,7 +572,6 @@ static void handle_bootstrap_impl(THD *t } mysql_parse(thd, thd->query(), length, &parser_state); - close_thread_tables(thd); // Free tables bootstrap_error= thd->is_error(); thd->protocol->end_statement(); @@ -1139,13 +1142,11 @@ bool dispatch_command(enum enum_server_c { char *beginning_of_next_stmt= (char*) parser_state.m_lip.found_semicolon; - - thd->protocol->end_statement(); - query_cache_end_of_result(thd); /* Multiple queries exits, execute them individually */ - close_thread_tables(thd); + thd->protocol->end_statement(); + query_cache_end_of_result(thd); ulong length= (ulong)(packet_end - beginning_of_next_stmt); log_slow_statement(thd); @@ -1197,38 +1198,54 @@ bool dispatch_command(enum enum_server_c char *fields, *packet_end= packet + packet_length, *arg_end; /* Locked closure of all tables */ TABLE_LIST table_list; - LEX_STRING conv_name; - - /* used as fields initializator */ - lex_start(thd); + LEX_STRING table_name; + LEX_STRING db; + /* + SHOW statements should not add the used tables to the list of tables + used in a transaction. + */ + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]); - bzero((char*) &table_list,sizeof(table_list)); - if (thd->copy_db_to(&table_list.db, &table_list.db_length)) + if (thd->copy_db_to(&db.str, &db.length)) break; /* We have name + wildcard in packet, separated by endzero */ arg_end= strend(packet); uint arg_length= arg_end - packet; - + /* Check given table name length. */ if (arg_length >= packet_length || arg_length > NAME_LEN) { my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } - thd->convert_string(&conv_name, system_charset_info, + thd->convert_string(&table_name, system_charset_info, packet, arg_length, thd->charset()); - if (check_table_name(conv_name.str, conv_name.length, FALSE)) + if (check_table_name(table_name.str, table_name.length, FALSE)) { /* this is OK due to convert_string() null-terminating the string */ - my_error(ER_WRONG_TABLE_NAME, MYF(0), conv_name.str); + my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str); break; } - - table_list.alias= table_list.table_name= conv_name.str; packet= arg_end + 1; + mysql_reset_thd_for_next_command(thd); + lex_start(thd); + /* Must be before we init the table list. */ + if (lower_case_table_names) + table_name.length= my_casedn_str(files_charset_info, table_name.str); + table_list.init_one_table(db.str, db.length, table_name.str, + table_name.length, table_name.str, TL_READ); + /* + Init TABLE_LIST members necessary when the undelrying + table is view. + */ + table_list.select_lex= &(thd->lex->select_lex); + thd->lex-> + select_lex.table_list.link_in_list(&table_list, + &table_list.next_local); + thd->lex->add_to_query_tables(&table_list); if (is_infoschema_db(table_list.db, table_list.db_length)) { @@ -1242,32 +1259,23 @@ bool dispatch_command(enum enum_server_c break; thd->set_query(fields, query_length); general_log_print(thd, command, "%s %s", table_list.table_name, fields); - if (lower_case_table_names) - my_casedn_str(files_charset_info, table_list.table_name); - if (check_access(thd, SELECT_ACL, table_list.db, - &table_list.grant.privilege, - &table_list.grant.m_internal, - 0, 0)) - break; - if (check_grant(thd, SELECT_ACL, &table_list, TRUE, UINT_MAX, FALSE)) + if (check_table_access(thd, SELECT_ACL, &table_list, + TRUE, UINT_MAX, FALSE)) break; - /* init structures for VIEW processing */ - table_list.select_lex= &(thd->lex->select_lex); - - lex_start(thd); - mysql_reset_thd_for_next_command(thd); - - thd->lex-> - select_lex.table_list.link_in_list(&table_list, - &table_list.next_local); - thd->lex->add_to_query_tables(&table_list); - init_mdl_requests(&table_list); - - /* switch on VIEW optimisation: do not fill temporary tables */ + /* + Turn on an optimization relevant if the underlying table + is a view: do not fill derived tables. + */ thd->lex->sql_command= SQLCOM_SHOW_FIELDS; + mysqld_list_fields(thd,&table_list,fields); thd->lex->unit.cleanup(); + /* No need to rollback statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + thd->cleanup_after_query(); break; } @@ -1315,7 +1323,6 @@ bool dispatch_command(enum enum_server_c ulong options= (ulong) (uchar) packet[0]; if (trans_commit_implicit(thd)) break; - close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); if (check_global_access(thd,RELOAD_ACL)) break; @@ -1377,7 +1384,6 @@ bool dispatch_command(enum enum_server_c DBUG_PRINT("quit",("Got shutdown command for level %u", level)); general_log_print(thd, command, NullS); my_eof(thd); - close_thread_tables(thd); // Free before kill kill_mysql(); error=TRUE; break; @@ -1480,29 +1486,9 @@ bool dispatch_command(enum enum_server_c my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } - - /* report error issued during command execution */ - if (thd->killed_errno()) - { - if (! thd->stmt_da->is_set()) - thd->send_kill_message(); - } - if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) - { - thd->killed= THD::NOT_KILLED; - thd->mysys_var->abort= 0; - } - - /* If commit fails, we should be able to reset the OK status. */ - thd->stmt_da->can_overwrite_status= TRUE; - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); - thd->stmt_da->can_overwrite_status= FALSE; - - thd->transaction.stmt.reset(); - - thd->proc_info= "closing tables"; - /* Free tables */ - close_thread_tables(thd); + DBUG_ASSERT(thd->derived_tables == NULL && + (thd->open_tables == NULL || + (thd->locked_tables_mode == LTM_LOCK_TABLES))); thd->protocol->end_statement(); query_cache_end_of_result(thd); @@ -1715,6 +1701,9 @@ int prepare_schema_table(THD *thd, LEX * In brief: take exclusive locks, expel tables from the table cache, reopen the tables, enter the 'LOCKED TABLES' mode, downgrade the locks. + Note: the function is written to be called from + mysql_execute_command(), it is not reusable in arbitrary + execution context. Required privileges ------------------- @@ -1816,9 +1805,9 @@ static bool flush_tables_with_read_lock( &lock_tables_prelocking_strategy) || thd->locked_tables_list.init_locked_tables(thd)) { - close_thread_tables(thd); goto error; } + thd->variables.option_bits|= OPTION_TABLE_LOCK; /* Downgrade the exclusive locks. @@ -2041,6 +2030,7 @@ mysql_execute_command(THD *thd) thd->work_part_info= 0; #endif + DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt); /* In many cases first table of main SELECT_LEX have special meaning => check that it is first table in global list and relink it first in @@ -2223,7 +2213,6 @@ mysql_execute_command(THD *thd) if (trans_commit_implicit(thd)) goto error; /* Close tables and release metadata locks. */ - close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); } @@ -3536,24 +3525,27 @@ end_with_restore_list: done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes false, mysqldump will not work. */ - thd->locked_tables_list.unlock_locked_tables(thd); if (thd->variables.option_bits & OPTION_TABLE_LOCK) { - trans_commit_implicit(thd); + res= trans_commit_implicit(thd); + thd->locked_tables_list.unlock_locked_tables(thd); thd->mdl_context.release_transactional_locks(); thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); } if (thd->global_read_lock.is_acquired()) thd->global_read_lock.unlock_global_read_lock(thd); + if (res) + goto error; my_ok(thd); break; case SQLCOM_LOCK_TABLES: + /* We must end the transaction first, regardless of anything */ + res= trans_commit_implicit(thd); thd->locked_tables_list.unlock_locked_tables(thd); - /* we must end the trasaction first, regardless of anything */ - if (trans_commit_implicit(thd)) - goto error; - /* release transactional metadata locks. */ + /* Release transactional metadata locks. */ thd->mdl_context.release_transactional_locks(); + if (res) + goto error; if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; @@ -3581,12 +3573,8 @@ end_with_restore_list: can free its locks if LOCK TABLES locked some tables before finding that it can't lock a table in its list */ - trans_rollback_stmt(thd); trans_commit_implicit(thd); - /* - Close tables and release metadata locks otherwise a later call to - close_thread_tables might not release the locks if autocommit is off. - */ + /* Close tables and release metadata locks. */ close_thread_tables(thd); DBUG_ASSERT(!thd->locked_tables_mode); thd->mdl_context.release_transactional_locks(); @@ -4205,9 +4193,7 @@ end_with_restore_list: locks in the MDL context, so there is no risk to deadlock. */ - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); /* Check if the definer exists on slave, then use definer privilege to insert routine privileges to mysql.procs_priv. @@ -4484,9 +4470,7 @@ create_sp_error: locks in the MDL context, so there is no risk to deadlock. */ - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); if (sp_automatic_privileges && !opt_noacl && sp_revoke_privileges(thd, db, name, @@ -4778,17 +4762,60 @@ finish: DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() || thd->in_multi_stmt_transaction_mode()); + + if (! thd->in_sub_stmt) + { + /* report error issued during command execution */ + if (thd->killed_errno()) + { + if (! thd->stmt_da->is_set()) + thd->send_kill_message(); + } + if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) + { + thd->killed= THD::NOT_KILLED; + thd->mysys_var->abort= 0; + } + if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR)) + trans_rollback_stmt(thd); + else + { + /* If commit fails, we should be able to reset the OK status. */ + thd->stmt_da->can_overwrite_status= TRUE; + trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + } + } + + lex->unit.cleanup(); + /* Free tables */ + thd_proc_info(thd, "closing tables"); + close_thread_tables(thd); + thd_proc_info(thd, 0); + if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) { + /* No transaction control allowed in sub-statements. */ + DBUG_ASSERT(! thd->in_sub_stmt); /* If commit fails, we should be able to reset the OK status. */ thd->stmt_da->can_overwrite_status= TRUE; - /* Commit or rollback the statement transaction. */ - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); /* Commit the normal transaction if one is active. */ trans_commit_implicit(thd); thd->stmt_da->can_overwrite_status= FALSE; - /* Close tables and release metadata locks. */ - close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) + { + /* + - If inside a multi-statement transaction, + defer the release of metadata locks until the current + transaction is either committed or rolled back. This prevents + other statements from modifying the table for the entire + duration of this transaction. This provides commit ordering + and guarantees serializability across multiple transactions. + - If in autocommit mode, or outside a transactional context, + automatically release metadata locks of the current statement. + */ thd->mdl_context.release_transactional_locks(); } @@ -5886,12 +5913,6 @@ void mysql_parse(THD *thd, const char *i query_cache_abort(&thd->query_cache_tls); } - if (thd->lex->sphead) - { - delete thd->lex->sphead; - thd->lex->sphead= 0; - } - lex->unit.cleanup(); thd_proc_info(thd, "freeing items"); thd->end_statement(); thd->cleanup_after_query(); @@ -6997,11 +7018,15 @@ uint kill_one_thread(THD *thd, ulong id, only_kill_query Should it kill the query or the connection */ +static void sql_kill(THD *thd, ulong id, bool only_kill_query) { uint error; if (!(error= kill_one_thread(thd, id, only_kill_query))) - my_ok(thd); + { + if (! thd->killed) + my_ok(thd); + } else my_error(error, MYF(0), id); } === modified file 'sql/sql_parse.h' --- a/sql/sql_parse.h 2010-07-15 17:45:08 +0000 +++ b/sql/sql_parse.h 2010-07-26 16:13:09 +0000 @@ -51,7 +51,6 @@ bool parse_sql(THD *thd, Object_creation_ctx *creation_ctx); uint kill_one_thread(THD *thd, ulong id, bool only_kill_query); -void sql_kill(THD *thd, ulong id, bool only_kill_query); void free_items(Item *item); void cleanup_items(Item *item); === modified file 'sql/sql_partition.cc' --- a/sql/sql_partition.cc 2010-07-08 21:20:08 +0000 +++ b/sql/sql_partition.cc 2010-07-26 16:13:09 +0000 @@ -59,7 +59,7 @@ #include "my_md5.h" #include "transaction.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_all_tables_for_name #include "sql_table.h" // build_table_filename, // build_table_shadow_filename, // table_to_filename @@ -6758,7 +6758,6 @@ uint fast_alter_partition_table(THD *thd table_list, FALSE, NULL, written_bin_log)); err: - close_thread_tables(thd); DBUG_RETURN(TRUE); } #endif === modified file 'sql/sql_plugin.cc' --- a/sql/sql_plugin.cc 2010-07-08 21:20:08 +0000 +++ b/sql/sql_plugin.cc 2010-07-26 16:13:09 +0000 @@ -21,7 +21,7 @@ #include "sql_locale.h" #include "sql_plugin.h" #include "sql_parse.h" // check_table_access -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "key.h" // key_copy #include "sql_show.h" // remove_status_vars, add_status_vars #include "strfunc.h" // find_set @@ -1511,8 +1511,8 @@ static void plugin_load(MEM_ROOT *tmp_ro sql_print_error(ER(ER_GET_ERRNO), my_errno); end_read_record(&read_record_info); table->m_needs_reopen= TRUE; // Force close to free memory + close_mysql_tables(new_thd); end: - close_thread_tables(new_thd); /* Remember that we don't have a THD */ my_pthread_setspecific_ptr(THR_THD, 0); DBUG_VOID_RETURN; === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2010-06-28 20:32:09 +0000 +++ b/sql/sql_prepare.cc 2010-07-26 16:13:09 +0000 @@ -90,7 +90,7 @@ When one supplies long data for a placeh #include "set_var.h" #include "sql_prepare.h" #include "sql_parse.h" // insert_precheck, update_precheck, delete_precheck -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // open_normal_and_derived_tables #include "sql_cache.h" // query_cache_* #include "sql_view.h" // create_view_precheck #include "sql_delete.h" // mysql_prepare_delete @@ -2989,12 +2989,6 @@ Execute_sql_statement::execute_server_co error= mysql_execute_command(thd); - if (thd->killed_errno()) - { - if (! thd->stmt_da->is_set()) - thd->send_kill_message(); - } - /* report error issued during command execution */ if (error == 0 && thd->spcont == NULL) general_log_write(thd, COM_STMT_EXECUTE, @@ -3102,13 +3096,8 @@ void Prepared_statement::cleanup_stmt() DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: 0x%lx", (long) this)); - delete lex->sphead; - lex->sphead= 0; - /* The order is important */ - lex->unit.cleanup(); cleanup_items(free_list); thd->cleanup_after_query(); - close_thread_tables(thd); thd->rollback_item_tree_changes(); DBUG_VOID_RETURN; @@ -3272,21 +3261,16 @@ bool Prepared_statement::prepare(const c to PREPARE stmt FROM "CREATE PROCEDURE ..." */ DBUG_ASSERT(lex->sphead == NULL || error != 0); - if (lex->sphead) - { - delete lex->sphead; - lex->sphead= NULL; - } + /* The order is important */ + lex->unit.cleanup(); + + /* No need to commit statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); lex_end(lex); cleanup_stmt(); - /* - If not inside a multi-statement transaction, the metadata - locks have already been released and our savepoint points - to ticket which has been released as well. - */ - if (thd->in_multi_stmt_transaction_mode()) - thd->mdl_context.rollback_to_savepoint(mdl_savepoint); thd->restore_backup_statement(this, &stmt_backup); thd->stmt_arena= old_stmt_arena; @@ -3393,11 +3377,6 @@ Prepared_statement::set_parameters(Strin and execute of a new statement. If this happens repeatedly more than MAX_REPREPARE_ATTEMPTS times, we give up. - In future we need to be able to keep the metadata locks between - prepare and execute, but right now open_and_lock_tables(), as - well as close_thread_tables() are buried deep inside - execution code (mysql_execute_command()). - @return TRUE if an error, FALSE if success @retval TRUE either MAX_REPREPARE_ATTEMPTS has been reached, or some general error @@ -3484,11 +3463,6 @@ Prepared_statement::execute_server_runna error= server_runnable->execute_server_code(thd); - delete lex->sphead; - lex->sphead= 0; - /* The order is important */ - lex->unit.cleanup(); - close_thread_tables(thd); thd->cleanup_after_query(); thd->restore_active_arena(this, &stmt_backup); === modified file 'sql/sql_priv.h' --- a/sql/sql_priv.h 2010-06-17 13:31:51 +0000 +++ b/sql/sql_priv.h 2010-07-26 16:13:09 +0000 @@ -135,6 +135,16 @@ extern char err_shared_dir[]; Type of locks to be acquired is specified directly. */ #define SELECT_HIGH_PRIORITY (1ULL << 34) // SELECT, user +/** + Is set in slave SQL thread when there was an + error on master, which, when is not reproducible + on slave (i.e. the query succeeds on slave), + is not terminal to the state of repliation, + and should be ignored. The slave SQL thread, + however, needs to rollback the effects of the + succeeded statement to keep replication consistent. +*/ +#define OPTION_MASTER_SQL_ERROR (1ULL << 35) /* The rest of the file is included in the server only */ === modified file 'sql/sql_servers.cc' --- a/sql/sql_servers.cc 2010-03-31 14:05:33 +0000 +++ b/sql/sql_servers.cc 2010-07-26 16:13:09 +0000 @@ -36,7 +36,7 @@ #include "sql_priv.h" #include "sql_servers.h" #include "unireg.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "records.h" // init_read_record, end_read_record #include "hash_filo.h" #include @@ -280,9 +280,7 @@ bool servers_reload(THD *thd) } end: - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); DBUG_PRINT("info", ("unlocking servers_cache")); mysql_rwlock_unlock(&THR_LOCK_servers); DBUG_RETURN(return_val); @@ -535,6 +533,7 @@ int insert_server_record(TABLE *table, F { int error; DBUG_ENTER("insert_server_record"); + tmp_disable_binlog(table->in_use); table->use_all_columns(); empty_record(table); @@ -571,6 +570,8 @@ int insert_server_record(TABLE *table, F } else error= ER_FOREIGN_SERVER_EXISTS; + + reenable_binlog(table->in_use); DBUG_RETURN(error); } @@ -625,7 +626,7 @@ int drop_server(THD *thd, LEX_SERVER_OPT error= delete_server_record(table, name.str, name.length); /* close the servers table before we call closed_cached_connection_tables */ - close_thread_tables(thd); + close_mysql_tables(thd); if (close_cached_connection_tables(thd, TRUE, &name)) { @@ -880,6 +881,7 @@ update_server_record(TABLE *table, FOREI { int error=0; DBUG_ENTER("update_server_record"); + tmp_disable_binlog(table->in_use); table->use_all_columns(); /* set the field that's the PK to the value we're looking for */ table->field[0]->store(server->server_name, @@ -913,6 +915,7 @@ update_server_record(TABLE *table, FOREI } end: + reenable_binlog(table->in_use); DBUG_RETURN(error); } @@ -938,6 +941,7 @@ delete_server_record(TABLE *table, { int error; DBUG_ENTER("delete_server_record"); + tmp_disable_binlog(table->in_use); table->use_all_columns(); /* set the field that's the PK to the value we're looking for */ @@ -959,6 +963,7 @@ delete_server_record(TABLE *table, table->file->print_error(error, MYF(0)); } + reenable_binlog(table->in_use); DBUG_RETURN(error); } @@ -1050,7 +1055,7 @@ int alter_server(THD *thd, LEX_SERVER_OP error= update_server(thd, existing, altered); /* close the servers table before we call closed_cached_connection_tables */ - close_thread_tables(thd); + close_mysql_tables(thd); if (close_cached_connection_tables(thd, FALSE, &name)) { === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2010-07-13 08:39:24 +0000 +++ b/sql/sql_table.cc 2010-07-26 16:13:09 +0000 @@ -2285,18 +2285,13 @@ err: { /* Under LOCK TABLES we should release meta-data locks on the tables - which were dropped. Otherwise we can rely on close_thread_tables() - doing this. Unfortunately in this case we are likely to get more - false positives in try_acquire_lock() function. So - it makes sense to remove exclusive meta-data locks in all cases. + which were dropped. Leave LOCK TABLES mode if we managed to drop all tables which were locked. Additional check for 'non_temp_tables_count' is to avoid leaving LOCK TABLES mode if we have dropped only temporary tables. */ - if (! thd->locked_tables_mode) - thd->mdl_context.release_transactional_locks(); - else + if (thd->locked_tables_mode) { if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0) { @@ -2305,7 +2300,8 @@ err: } for (table= tables; table; table= table->next_local) { - if (table->mdl_request.ticket) + /* Drop locks for all successfully dropped tables. */ + if (table->table == NULL && table->mdl_request.ticket) { /* Under LOCK TABLES we may have several instances of table open @@ -2316,6 +2312,10 @@ err: } } } + /* + Rely on the caller to implicitly commit the transaction + and release metadata locks. + */ } end: @@ -4214,8 +4214,14 @@ warn: } -/* - Database and name-locking aware wrapper for mysql_create_table_no_lock(), +/** + Implementation of SQLCOM_CREATE_TABLE. + + Take the metadata locks (including a shared lock on the affected + schema) and create the table. Is written to be called from + mysql_execute_command(), to which it delegates the common parts + with other commands (i.e. implicit commit before and after, + close of thread tables. */ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, @@ -4231,7 +4237,7 @@ bool mysql_create_table(THD *thd, TABLE_ if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) { result= TRUE; - goto unlock; + goto end; } /* Got lock. */ @@ -4253,16 +4259,7 @@ bool mysql_create_table(THD *thd, TABLE_ !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) result= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); - if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) - { - /* - close_thread_tables() takes care about both closing open tables (which - might be still around in case of error) and releasing metadata locks. - */ - close_thread_tables(thd); - } - -unlock: +end: DBUG_RETURN(result); } @@ -4752,6 +4749,7 @@ static bool mysql_admin_table(THD* thd, trans_rollback_stmt(thd); trans_rollback(thd); close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); DBUG_PRINT("admin", ("simple error, admin next table")); continue; case -1: // error, message could be written to net @@ -5038,11 +5036,11 @@ send_result_message: trans_commit_stmt(thd); trans_commit(thd); close_thread_tables(thd); - table->table= NULL; thd->mdl_context.release_transactional_locks(); + table->table= NULL; if (!result_code) // recreation went ok { - /* Clear the ticket released in close_thread_tables(). */ + /* Clear the ticket released above. */ table->mdl_request.ticket= NULL; DEBUG_SYNC(thd, "ha_admin_open_ltable"); table->mdl_request.set_type(MDL_SHARED_WRITE); @@ -6729,13 +6727,11 @@ bool mysql_alter_table(THD *thd,char *ne goto err; DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000);); error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); - /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err; error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); - /* COND_refresh will be signaled in close_thread_tables() */ break; default: DBUG_ASSERT(FALSE); @@ -6821,8 +6817,8 @@ bool mysql_alter_table(THD *thd,char *ne { /* Under LOCK TABLES we should adjust meta-data locks before finishing - statement. Otherwise we can rely on close_thread_tables() releasing - them. + statement. Otherwise we can rely on them being released + along with the implicit commit. */ if (new_name != table_name || new_db != db) { @@ -7360,8 +7356,8 @@ bool mysql_alter_table(THD *thd,char *ne 5) Write statement to the binary log. 6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we remove placeholders and release metadata locks. - 7) If we are not not under LOCK TABLES we rely on close_thread_tables() - call to remove placeholders and releasing metadata locks. + 7) If we are not not under LOCK TABLES we rely on the caller + (mysql_execute_command()) to release metadata locks. */ thd_proc_info(thd, "rename result table"); @@ -7990,7 +7986,13 @@ bool mysql_checksum_table(THD *thd, TABL } } thd->clear_error(); + if (! thd->in_sub_stmt) + trans_rollback_stmt(thd); close_thread_tables(thd); + /* + Don't release metadata locks, this will be done at + statement end. + */ table->table=0; // For query cache } if (protocol->write()) @@ -8000,10 +8002,7 @@ bool mysql_checksum_table(THD *thd, TABL my_eof(thd); DBUG_RETURN(FALSE); - err: - close_thread_tables(thd); // Shouldn't be needed - if (table) - table->table=0; +err: DBUG_RETURN(TRUE); } === modified file 'sql/sql_trigger.cc' --- a/sql/sql_trigger.cc 2010-06-17 13:31:51 +0000 +++ b/sql/sql_trigger.cc 2010-07-26 16:13:09 +0000 @@ -540,9 +540,9 @@ end: } /* - If we are under LOCK TABLES we should restore original state of meta-data - locks. Otherwise call to close_thread_tables() will take care about both - TABLE instance created by open_n_lock_single_table() and metadata lock. + If we are under LOCK TABLES we should restore original state of + meta-data locks. Otherwise all locks will be released along + with the implicit commit. */ if (thd->locked_tables_mode && tables && lock_upgrade_done) mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE); @@ -1321,6 +1321,7 @@ bool Table_triggers_list::check_n_load(T thd->reset_db((char*) db, strlen(db)); while ((trg_create_str= it++)) { + sp_head *sp; trg_sql_mode= itm++; LEX_STRING *trg_definer= it_definer++; @@ -1357,13 +1358,14 @@ bool Table_triggers_list::check_n_load(T */ lex.set_trg_event_type_for_tables(); - lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); - int event= lex.trg_chistics.event; int action_time= lex.trg_chistics.action_time; - lex.sphead->set_creation_ctx(creation_ctx); - triggers->bodies[event][action_time]= lex.sphead; + sp= triggers->bodies[event][action_time]= lex.sphead; + lex.sphead= NULL; /* Prevent double cleanup. */ + + sp->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); + sp->set_creation_ctx(creation_ctx); if (!trg_definer->length) { @@ -1376,27 +1378,26 @@ bool Table_triggers_list::check_n_load(T push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER), (const char*) db, - (const char*) lex.sphead->m_name.str); + (const char*) sp->m_name.str); /* Set definer to the '' to correct displaying in the information schema. */ - lex.sphead->set_definer((char*) "", 0); + sp->set_definer((char*) "", 0); /* Triggers without definer information are executed under the authorization of the invoker. */ - lex.sphead->m_chistics->suid= SP_IS_NOT_SUID; + sp->m_chistics->suid= SP_IS_NOT_SUID; } else - lex.sphead->set_definer(trg_definer->str, trg_definer->length); + sp->set_definer(trg_definer->str, trg_definer->length); - if (triggers->names_list.push_back(&lex.sphead->m_name, - &table->mem_root)) + if (triggers->names_list.push_back(&sp->m_name, &table->mem_root)) goto err_with_lex_cleanup; if (!(on_table_name= alloc_lex_string(&table->mem_root))) === modified file 'sql/sql_udf.cc' --- a/sql/sql_udf.cc 2010-06-11 15:28:18 +0000 +++ b/sql/sql_udf.cc 2010-07-26 16:13:09 +0000 @@ -33,7 +33,7 @@ #include "sql_priv.h" #include "unireg.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "sql_parse.h" // check_identifier_name #include "sql_table.h" // write_bin_log #include "records.h" // init_read_record, end_read_record @@ -251,7 +251,7 @@ void udf_init() table->m_needs_reopen= TRUE; // Force close to free memory end: - close_thread_tables(new_thd); + close_mysql_tables(new_thd); delete new_thd; /* Remember that we don't have a THD */ my_pthread_setspecific_ptr(THR_THD, 0); === modified file 'sql/sys_vars.cc' --- a/sql/sys_vars.cc 2010-07-15 17:45:08 +0000 +++ b/sql/sys_vars.cc 2010-07-26 16:13:09 +0000 @@ -2203,14 +2203,21 @@ static bool fix_autocommit(sys_var *self thd->variables.option_bits & OPTION_NOT_AUTOCOMMIT) { // activating autocommit - if (trans_commit(thd)) + if (trans_commit_stmt(thd) || trans_commit(thd)) { thd->variables.option_bits&= ~OPTION_AUTOCOMMIT; return true; } - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); - + /* + Don't close thread tables or release metadata locks: if we do so, we + risk releasing locks/closing tables of expressions used to assign + other variables, as in: + set @var=my_stored_function1(), @@autocommit=1, @var2=(select max(a) + from my_table), ... + The locks will be released at statement end anyway, as SET + statement that assigns autocommit is marked to commit + transaction implicitly at the end (@sa stmt_causes_implicitcommit()). + */ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_NOT_AUTOCOMMIT); thd->transaction.all.modified_non_trans_table= false; === modified file 'sql/transaction.cc' --- a/sql/transaction.cc 2010-06-25 07:32:24 +0000 +++ b/sql/transaction.cc 2010-07-26 16:13:09 +0000 @@ -28,6 +28,12 @@ static bool trans_check(THD *thd) enum xa_states xa_state= thd->transaction.xid_state.xa_state; DBUG_ENTER("trans_check"); + /* + Always commit statement transaction before manipulating with + the normal one. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + if (unlikely(thd->in_sub_stmt)) my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); if (xa_state != XA_NOTR) @@ -252,6 +258,14 @@ bool trans_commit_stmt(THD *thd) { DBUG_ENTER("trans_commit_stmt"); int res= FALSE; + /* + We currently don't invoke commit/rollback at end of + a sub-statement. In future, we perhaps should take + a savepoint for each nested statement, and release the + savepoint when statement has succeeded. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + if (thd->transaction.stmt.ha_list) { res= ha_commit_trans(thd, FALSE); @@ -267,6 +281,9 @@ bool trans_commit_stmt(THD *thd) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); else RUN_HOOK(transaction, after_commit, (thd, FALSE)); + + thd->transaction.stmt.reset(); + DBUG_RETURN(test(res)); } @@ -283,6 +300,14 @@ bool trans_rollback_stmt(THD *thd) { DBUG_ENTER("trans_rollback_stmt"); + /* + We currently don't invoke commit/rollback at end of + a sub-statement. In future, we perhaps should take + a savepoint for each nested statement, and release the + savepoint when statement has succeeded. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + if (thd->transaction.stmt.ha_list) { ha_rollback_trans(thd, FALSE); @@ -294,6 +319,8 @@ bool trans_rollback_stmt(THD *thd) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + thd->transaction.stmt.reset(); + DBUG_RETURN(FALSE); } === modified file 'sql/tztime.cc' --- a/sql/tztime.cc 2010-07-15 11:13:30 +0000 +++ b/sql/tztime.cc 2010-07-26 16:13:09 +0000 @@ -50,13 +50,6 @@ // MYSQL_LOCK_IGNORE_TIMEOUT /* - This forward declaration is needed because including sql_base.h - causes further includes. [TODO] Eliminate this forward declaration - and include a file with the prototype instead. -*/ -extern void close_thread_tables(THD *thd); - -/* Now we don't use abbreviations in server but we will do this in future. */ #if defined(TZINFO2SQL) || defined(TESTTIME) @@ -1784,10 +1777,7 @@ end_with_setting_default_tz: end_with_close: if (time_zone_tables_exist) - { - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); - } + close_mysql_tables(thd); end_with_cleanup: --Boundary_(ID_Hy+aQU8kVH2LKooryHlAnQ) MIME-version: 1.0 Content-type: text/bzr-bundle; CHARSET=US-ASCII; name="bzr/kostja@stripped" Content-transfer-encoding: 7BIT Content-disposition: inline; filename="bzr/kostja@stripped" # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: kostja@stripped # target_branch: file:///opt/local/work/trunk-runtime/ # testament_sha1: 8ddc72944fdeb662ef0a111f862e9efa3cbf24e4 # timestamp: 2010-07-26 20:13:24 +0400 # source_branch: file:///home/kostja/work/trunk-runtime-lockopen/ # base_revision_id: jon.hauglid@stripped\ # tx4c71abu8tbihhk # # Begin bundle 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 --Boundary_(ID_Hy+aQU8kVH2LKooryHlAnQ)--