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.
This commit is contained in:
parent
c67cf159e9
commit
ec2c3bf2c1
@ -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;
|
||||
}
|
||||
|
||||
|
212
sql/sql_parse.cc
212
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,14 +1198,16 @@ 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
|
||||
@ -1218,17 +1221,31 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
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