A pre-requisite patch for the fix for Bug#52044.
This patch also fixes Bug#55452 "SET PASSWORD is replicated twice in RBR mode". The goal of this patch is to remove the release of metadata locks from close_thread_tables(). This is necessary to not mistakenly release the locks in the course of a multi-step operation that involves multiple close_thread_tables() or close_tables_for_reopen(). On the same token, move statement commit outside close_thread_tables(). Other cleanups: 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. Simplify the back off condition in Open_table_context. Streamline metadata lock handling in LOCK TABLES implementation. Add asserts to ensure correct life cycle of statement transaction in a session. Remove a piece of dead code that has also become redundant after the fix for Bug 37521. 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 <view> 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 on the database name and the global intention exclusive 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 drop 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_class.cc: Remove a piece of dead code that has also become redundant after the fix for Bug 37521. The code became dead when my_eof() was made a non-protocol method, but a method that merely modifies the diagnostics area. The code became redundant with the fix for Bug#37521, when we started to cal close_thread_tables() before Protocol::end_statement(). 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().
This commit is contained in:
parent
c9e579bbb0
commit
36290c0923
@ -1677,3 +1677,25 @@ SET @@sql_quote_show_create = @sql_quote_show_create_saved;
|
||||
|
||||
# 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;
|
||||
|
@ -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;
|
||||
|
@ -165,10 +165,6 @@ master-bin.000001 # Table_map # # table_id: # (test.tt_1)
|
||||
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-
|
||||
|
@ -1405,4 +1405,30 @@ SET @@sql_quote_show_create = @sql_quote_show_create_saved;
|
||||
--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;
|
||||
|
||||
|
||||
###########################################################################
|
||||
|
@ -1402,6 +1402,8 @@ Event_job_data::execute(THD *thd, bool drop)
|
||||
*/
|
||||
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 drop)
|
||||
"[%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 drop)
|
||||
"[%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 drop)
|
||||
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 drop)
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -518,17 +518,20 @@ Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table,
|
||||
*/
|
||||
|
||||
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(THD *thd, TABLE_LIST *tables,
|
||||
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(THD *thd, enum thr_lock_type lock_type,
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
|
||||
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 *thd, Event_parse_data *parse_data,
|
||||
|
||||
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, LEX_STRING db, LEX_STRING name,
|
||||
|
||||
end:
|
||||
if (table)
|
||||
close_thread_tables(thd);
|
||||
close_mysql_tables(thd);
|
||||
|
||||
DBUG_RETURN(test(ret));
|
||||
}
|
||||
@ -933,34 +935,14 @@ Event_db_repository::find_named_event(LEX_STRING db, LEX_STRING name,
|
||||
|
||||
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_field(THD *thd,
|
||||
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_field(THD *thd,
|
||||
}
|
||||
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(THD *thd, LEX_STRING dbname,
|
||||
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(THD *thd)
|
||||
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(THD *thd)
|
||||
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(THD *thd)
|
||||
{
|
||||
if (table_intact.check(tables.table, &event_table_def))
|
||||
ret= 1;
|
||||
close_thread_tables(thd);
|
||||
close_mysql_tables(thd);
|
||||
}
|
||||
|
||||
DBUG_RETURN(test(ret));
|
||||
|
@ -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);
|
||||
|
@ -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, TABLE_LIST *tables, COND * /* cond */)
|
||||
{
|
||||
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, TABLE_LIST *tables, COND * /* cond */)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -7417,7 +7417,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
|
||||
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();
|
||||
}
|
||||
|
@ -298,13 +298,6 @@ static void run_query(THD *thd, char *buf, char *end,
|
||||
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, void *_row)
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1145,6 +1145,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 +1160,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 +1342,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 +1350,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);
|
||||
}
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -3332,6 +3332,19 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
|
||||
|
||||
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(Relay_log_info const *rli,
|
||||
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_error, thd->query());
|
||||
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,25 +3444,7 @@ Default database: '%s'. Query: '%s'",
|
||||
DBUG_PRINT("info",("error ignored"));
|
||||
clear_all_errors(thd, const_cast<Relay_log_info*>(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.
|
||||
*/
|
||||
@ -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_log_info const *rli)
|
||||
/* 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_log_info const *rli)
|
||||
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<Relay_log_info*>(rli)->slave_close_thread_tables(thd);
|
||||
DBUG_RETURN(ERR_BAD_TABLE_DEF);
|
||||
|
@ -1257,7 +1257,23 @@ void Relay_log_info::clear_tables_to_lock()
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
16
sql/sp.cc
16
sql/sp.cc
@ -450,10 +450,7 @@ static TABLE *open_proc_table_for_update(THD *thd)
|
||||
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_name *name, sp_head **sphp,
|
||||
}
|
||||
|
||||
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_head *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_name *name)
|
||||
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_name *name, st_sp_chistics *chistics)
|
||||
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, TABLE *proc_table, String *db,
|
||||
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;
|
||||
|
@ -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,17 +1997,24 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
||||
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_proc_info(thd, "closing tables");
|
||||
close_thread_tables(thd);
|
||||
thd_proc_info(thd, 0);
|
||||
|
||||
thd->rollback_item_tree_changes();
|
||||
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);
|
||||
|
||||
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(THD *thd, uint *nextp,
|
||||
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)
|
||||
{
|
||||
|
@ -682,6 +682,8 @@ public:
|
||||
{
|
||||
if (m_lex_resp)
|
||||
{
|
||||
/* Prevent endless recursion. */
|
||||
m_lex->sphead= NULL;
|
||||
lex_end(m_lex);
|
||||
delete m_lex;
|
||||
}
|
||||
|
@ -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 char *host, const char *user,
|
||||
/* 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 char *host, const char *user,
|
||||
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 char *host, const char *user,
|
||||
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_LIST *table_list,
|
||||
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_LIST *table_list,
|
||||
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_LIST *table_list, bool is_proc,
|
||||
|
||||
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 *db, List <LEX_USER> &list,
|
||||
|
||||
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 *db, List <LEX_USER> &list,
|
||||
}
|
||||
|
||||
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(THD *thd)
|
||||
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(THD *thd)
|
||||
}
|
||||
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_LIST *tables)
|
||||
|
||||
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 <LEX_USER> &list)
|
||||
result |= write_bin_log(thd, FALSE, thd->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 <LEX_USER> &list)
|
||||
result |= write_bin_log(thd, FALSE, thd->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 <LEX_USER> &list)
|
||||
result |= write_bin_log(thd, FALSE, thd->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 <LEX_USER> &list)
|
||||
write_bin_log(thd, FALSE, thd->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, const char *sp_db, const char *sp_name,
|
||||
|
||||
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 */
|
||||
|
155
sql/sql_base.cc
155
sql/sql_base.cc
@ -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 **table_ptr)
|
||||
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(THD *thd)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Leave LTM_LOCK_TABLES mode if it's been entered.
|
||||
|
||||
@ -3224,7 +3193,12 @@ Locked_tables_list::unlock_locked_tables(THD *thd)
|
||||
}
|
||||
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(THD *thd, uint flags)
|
||||
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_list, thr_lock_type lock_type,
|
||||
table= 0;
|
||||
|
||||
end:
|
||||
if (table == NULL)
|
||||
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, TABLE_LIST *tables,
|
||||
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, TABLE_LIST *tables,
|
||||
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, TABLE_LIST *tables,
|
||||
|
||||
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, TABLE_LIST **tables,
|
||||
/* 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, TABLE_LIST *table_list,
|
||||
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, TABLE_LIST *table_list,
|
||||
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_tables_backup *backup)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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, Open_tables_backup *backup)
|
||||
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);
|
||||
|
@ -240,6 +240,7 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
|
||||
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);
|
||||
|
@ -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)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "sql_select.h"
|
||||
#include "probes_mysql.h"
|
||||
#include "sql_parse.h" // mysql_execute_command
|
||||
#include "sql_base.h"
|
||||
|
||||
/****************************************************************************
|
||||
Declarations.
|
||||
@ -523,6 +524,7 @@ Sensitive_cursor::close()
|
||||
thd->derived_tables= derived_tables;
|
||||
thd->lock= lock;
|
||||
|
||||
close_thread_tables(thd);
|
||||
/* Is expected to at least close tables and empty thd->change_list */
|
||||
stmt_arena->cleanup_stmt();
|
||||
|
||||
|
@ -39,9 +39,10 @@ bool mysql_do(THD *thd, List<Item> &values)
|
||||
/*
|
||||
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);
|
||||
|
@ -59,7 +59,7 @@
|
||||
#include "key.h" // key_copy
|
||||
#include "sql_base.h" // insert_fields
|
||||
#include "sql_select.h"
|
||||
#include <assert.h>
|
||||
#include "transaction.h"
|
||||
|
||||
#define HANDLER_TABLES_HASH_SIZE 120
|
||||
|
||||
@ -309,9 +309,15 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
|
||||
}
|
||||
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"));
|
||||
|
@ -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);
|
||||
@ -2414,6 +2417,8 @@ bool Delayed_insert::open_and_lock_table()
|
||||
}
|
||||
if (!(table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
|
||||
{
|
||||
/* To rollback InnoDB statement transaction. */
|
||||
trans_rollback_stmt(&thd);
|
||||
my_error(ER_DELAYED_NOT_SUPPORTED, MYF(ME_FATALERROR),
|
||||
table_list.table_name);
|
||||
return TRUE;
|
||||
@ -2480,12 +2485,6 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
Open table requires an initialized lex in case the table is
|
||||
partitioned. The .frm file contains a partial SQL string which is
|
||||
parsed using a lex, that depends on initialized thd->lex.
|
||||
*/
|
||||
lex_start(thd);
|
||||
thd->lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
|
||||
/*
|
||||
Statement-based replication of INSERT DELAYED has problems with RAND()
|
||||
@ -2619,28 +2618,11 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
}
|
||||
|
||||
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 +2630,10 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
|
||||
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);
|
||||
|
@ -450,6 +450,9 @@ void lex_end(LEX *lex)
|
||||
}
|
||||
reset_dynamic(&lex->plugins);
|
||||
|
||||
delete lex->sphead;
|
||||
lex->sphead= NULL;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
214
sql/sql_parse.cc
214
sql/sql_parse.cc
@ -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 *thd)
|
||||
}
|
||||
|
||||
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_command command, THD *thd,
|
||||
{
|
||||
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_command command, THD *thd,
|
||||
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_command command, THD *thd,
|
||||
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))
|
||||
if (check_table_access(thd, SELECT_ACL, &table_list,
|
||||
TRUE, UINT_MAX, FALSE))
|
||||
break;
|
||||
if (check_grant(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_command command, THD *thd,
|
||||
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_command command, THD *thd,
|
||||
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_command command, THD *thd,
|
||||
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 *lex, Table_ident *table_ident,
|
||||
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(THD *thd, TABLE_LIST *all_tables)
|
||||
&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
|
||||
@ -2222,8 +2212,7 @@ mysql_execute_command(THD *thd)
|
||||
/* Commit the normal transaction if one is active. */
|
||||
if (trans_commit_implicit(thd))
|
||||
goto error;
|
||||
/* Close tables and release metadata locks. */
|
||||
close_thread_tables(thd);
|
||||
/* Release metadata locks acquired in this transaction. */
|
||||
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;
|
||||
@ -3576,17 +3568,14 @@ end_with_restore_list:
|
||||
|
||||
if (res)
|
||||
{
|
||||
trans_rollback_stmt(thd);
|
||||
/*
|
||||
Need to end the current transaction, so the storage engine (InnoDB)
|
||||
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 +4194,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 +4471,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 +4763,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 +5914,6 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
|
||||
|
||||
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 +7019,15 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 *table,
|
||||
table_list, FALSE, NULL,
|
||||
written_bin_log));
|
||||
err:
|
||||
close_thread_tables(thd);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
#endif
|
||||
|
@ -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_root, int *argc, char **argv)
|
||||
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;
|
||||
|
@ -90,7 +90,7 @@ When one supplies long data for a placeholder:
|
||||
#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_code(THD *thd)
|
||||
|
||||
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 char *packet, uint packet_len)
|
||||
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(String *expanded_query,
|
||||
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_runnable(Server_runnable *server_runnable)
|
||||
|
||||
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);
|
||||
|
@ -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 */
|
||||
|
@ -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 <m_ctype.h>
|
||||
@ -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, FOREIGN_SERVER *server)
|
||||
{
|
||||
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, FOREIGN_SERVER *server)
|
||||
}
|
||||
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_OPTIONS *server_options)
|
||||
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, FOREIGN_SERVER *server)
|
||||
{
|
||||
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, FOREIGN_SERVER *server)
|
||||
}
|
||||
|
||||
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_OPTIONS *server_options)
|
||||
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))
|
||||
{
|
||||
|
@ -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_LIST *create_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_LIST *create_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, TABLE_LIST* tables,
|
||||
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 *new_db, char *new_name,
|
||||
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 *new_db, char *new_name,
|
||||
{
|
||||
/*
|
||||
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 *new_db, char *new_name,
|
||||
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, TABLE_LIST *tables,
|
||||
}
|
||||
}
|
||||
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, TABLE_LIST *tables,
|
||||
my_eof(thd);
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
err:
|
||||
close_thread_tables(thd); // Shouldn't be needed
|
||||
if (table)
|
||||
table->table=0;
|
||||
err:
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
@ -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(THD *thd, const char *db,
|
||||
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(THD *thd, const char *db,
|
||||
*/
|
||||
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(THD *thd, const char *db,
|
||||
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)))
|
||||
|
@ -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);
|
||||
|
@ -2203,14 +2203,21 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type)
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -49,13 +49,6 @@
|
||||
#include "lock.h" // MYSQL_LOCK_IGNORE_FLUSH,
|
||||
// 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.
|
||||
*/
|
||||
@ -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:
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user