1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-6050 MySQL Bug#13036505 62540: TABLE LOCKS WITHIN STORED FUNCTIONS ARE BACK IN 5.5 WITH MIXED AND ROW BI

cherry-pick revno 4053
committer: Gopal Shankar <gopal.shankar@oracle.com>
branch nick: sf_mysql-5.6
timestamp: Fri 2012-07-20 12:25:34 +0530
message:
  Bug#13036505 62540: TABLE LOCKS WITHIN STORED FUNCTIONS ARE BACK IN
                      5.5 WITH MIXED AND ROW BI.
This commit is contained in:
Sergei Golubchik
2014-07-31 12:03:20 +02:00
parent de4a3c2a1d
commit 8867a499f7
9 changed files with 321 additions and 161 deletions

View File

@ -3517,9 +3517,12 @@ Open_table_context::recover_from_failed_open()
/*
Return a appropriate read lock type given a table object.
@param thd Thread context
@param prelocking_ctx Prelocking context.
@param table_list Table list element for table to be locked.
@param thd Thread context
@param prelocking_ctx Prelocking context.
@param table_list Table list element for table to be locked.
@param routine_modifies_data
Some routine that is invoked by statement
modifies data.
@remark Due to a statement-based replication limitation, statements such as
INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM need
@ -3532,9 +3535,13 @@ Open_table_context::recover_from_failed_open()
This also applies to SELECT/SET/DO statements which use stored
functions. Calls to such functions are going to be logged as a
whole and thus should be serialized against concurrent changes
to tables used by those functions. This can be avoided if functions
only read data but doing so requires more complex analysis than it
is done now.
to tables used by those functions. This is avoided when functions
do not modify data but only read it, since in this case nothing is
written to the binary log. Argument routine_modifies_data
denotes the same. So effectively, if the statement is not a
update query and routine_modifies_data is false, then
prelocking_placeholder does not take importance.
Furthermore, this does not apply to I_S and log tables as it's
always unsafe to replicate such tables under statement-based
replication as the table on the slave might contain other data
@ -3549,7 +3556,8 @@ Open_table_context::recover_from_failed_open()
thr_lock_type read_lock_type_for_table(THD *thd,
Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list)
TABLE_LIST *table_list,
bool routine_modifies_data)
{
/*
In cases when this function is called for a sub-statement executed in
@ -3564,7 +3572,7 @@ thr_lock_type read_lock_type_for_table(THD *thd,
(table_list->table->s->table_category == TABLE_CATEGORY_LOG) ||
(table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) ||
!(is_update_query(prelocking_ctx->sql_command) ||
table_list->prelocking_placeholder ||
(routine_modifies_data && table_list->prelocking_placeholder) ||
(thd->locked_tables_mode > LTM_LOCK_TABLES)))
return TL_READ;
else
@ -3577,19 +3585,21 @@ thr_lock_type read_lock_type_for_table(THD *thd,
and, if prelocking strategy prescribes so, extend the prelocking set
with tables and routines used by it.
@param[in] thd Thread context.
@param[in] prelocking_ctx Prelocking context.
@param[in] rt Element of prelocking set to be processed.
@param[in] prelocking_strategy Strategy which specifies how the
prelocking set should be extended when
one of its elements is processed.
@param[in] has_prelocking_list Indicates that prelocking set/list for
this statement has already been built.
@param[in] ot_ctx Context of open_table used to recover from
locking failures.
@param[out] need_prelocking Set to TRUE if it was detected that this
statement will require prelocked mode for
its execution, not touched otherwise.
@param[in] thd Thread context.
@param[in] prelocking_ctx Prelocking context.
@param[in] rt Element of prelocking set to be processed.
@param[in] prelocking_strategy Strategy which specifies how the
prelocking set should be extended when
one of its elements is processed.
@param[in] has_prelocking_list Indicates that prelocking set/list for
this statement has already been built.
@param[in] ot_ctx Context of open_table used to recover from
locking failures.
@param[out] need_prelocking Set to TRUE if it was detected that this
statement will require prelocked mode for
its execution, not touched otherwise.
@param[out] routine_modifies_data Set to TRUE if it was detected that this
routine does modify table data.
@retval FALSE Success.
@retval TRUE Failure (Conflicting metadata lock, OOM, other errors).
@ -3601,11 +3611,13 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
Prelocking_strategy *prelocking_strategy,
bool has_prelocking_list,
Open_table_context *ot_ctx,
bool *need_prelocking)
bool *need_prelocking, bool *routine_modifies_data)
{
MDL_key::enum_mdl_namespace mdl_type= rt->mdl_request.key.mdl_namespace();
DBUG_ENTER("open_and_process_routine");
*routine_modifies_data= false;
switch (mdl_type)
{
case MDL_key::FUNCTION:
@ -3658,10 +3670,13 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
DBUG_RETURN(TRUE);
/* 'sp' is NULL when there is no such routine. */
if (sp && !has_prelocking_list)
if (sp)
{
prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp,
need_prelocking);
*routine_modifies_data= sp->modifies_data();
if (!has_prelocking_list)
prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp,
need_prelocking);
}
}
else
@ -4006,16 +4021,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
goto end;
}
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
{
if (tables->lock_type == TL_WRITE_DEFAULT)
tables->table->reginfo.lock_type= thd->update_lock_default;
else if (tables->lock_type == TL_READ_DEFAULT)
tables->table->reginfo.lock_type=
read_lock_type_for_table(thd, lex, tables);
else
tables->table->reginfo.lock_type= tables->lock_type;
}
/* Copy grant information from TABLE_LIST instance to TABLE one. */
tables->table->grant= tables->grant;
/* Check and update metadata version of a base table. */
@ -4354,6 +4360,7 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
Open_table_context ot_ctx(thd, flags);
bool error= FALSE;
MEM_ROOT new_frm_mem;
bool some_routine_modifies_data= FALSE;
bool has_prelocking_list;
DBUG_ENTER("open_tables");
@ -4526,11 +4533,16 @@ restart:
sroutine_to_open= &rt->next, rt= rt->next)
{
bool need_prelocking= false;
bool routine_modifies_data;
TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
error= open_and_process_routine(thd, thd->lex, rt, prelocking_strategy,
has_prelocking_list, &ot_ctx,
&need_prelocking);
&need_prelocking,
&routine_modifies_data);
// Remember if any of SF modifies data.
some_routine_modifies_data|= routine_modifies_data;
if (need_prelocking && ! thd->lex->requires_prelocking())
thd->lex->mark_as_requiring_prelocking(save_query_tables_last);
@ -4570,6 +4582,10 @@ restart:
children, attach the children to their parents. At end of statement,
the children are detached. Attaching and detaching are always done,
even under LOCK TABLES.
We also convert all TL_WRITE_DEFAULT and TL_READ_DEFAULT locks to
appropriate "real" lock types to be used for locking and to be passed
to storage engine.
*/
for (tables= *start; tables; tables= tables->next_global)
{
@ -4586,6 +4602,19 @@ restart:
goto err;
}
}
/* Set appropriate TABLE::lock_type. */
if (tbl && tables->lock_type != TL_UNLOCK && !thd->locked_tables_mode)
{
if (tables->lock_type == TL_WRITE_DEFAULT)
tbl->reginfo.lock_type= thd->update_lock_default;
else if (tables->lock_type == TL_READ_DEFAULT)
tbl->reginfo.lock_type=
read_lock_type_for_table(thd, thd->lex, tables,
some_routine_modifies_data);
else
tbl->reginfo.lock_type= tables->lock_type;
}
}
err:
@ -4847,11 +4876,15 @@ static bool check_lock_and_start_stmt(THD *thd,
engine is important as, for example, InnoDB uses it to determine
what kind of row locks should be acquired when executing statement
in prelocked mode or under LOCK TABLES with @@innodb_table_locks = 0.
Last argument routine_modifies_data for read_lock_type_for_table()
is ignored, as prelocking placeholder will never be set here.
*/
DBUG_ASSERT(table_list->prelocking_placeholder == false);
if (table_list->lock_type == TL_WRITE_DEFAULT)
lock_type= thd->update_lock_default;
else if (table_list->lock_type == TL_READ_DEFAULT)
lock_type= read_lock_type_for_table(thd, prelocking_ctx, table_list);
lock_type= read_lock_type_for_table(thd, prelocking_ctx, table_list, true);
else
lock_type= table_list->lock_type;