mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Manual merge SP-locking improvements patch with current tree.
This commit is contained in:
168
sql/sql_parse.cc
168
sql/sql_parse.cc
@ -1453,105 +1453,6 @@ bool do_command(THD *thd)
|
||||
}
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
|
||||
static void release_local_lock(THD *thd, TABLE_LIST *locked_tables,
|
||||
bool old_innodb_table_locks)
|
||||
{
|
||||
if (locked_tables)
|
||||
{
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
thd->variables.innodb_table_locks= old_innodb_table_locks;
|
||||
#endif
|
||||
if (thd->locked_tables)
|
||||
sp_unlock_tables(thd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool process_nested_sp(THD *thd, LEX *lex, TABLE_LIST** locked_tables)
|
||||
{
|
||||
DBUG_ENTER("process_nested_sp");
|
||||
while (1)
|
||||
{
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (!thd->locked_tables &&
|
||||
lex->sql_command != SQLCOM_CREATE_TABLE &&
|
||||
lex->sql_command != SQLCOM_CREATE_VIEW)
|
||||
{
|
||||
MEM_ROOT *thdmemroot= NULL;
|
||||
|
||||
sp_merge_routine_tables(thd, lex);
|
||||
// QQ Preopen tables to find views and triggers.
|
||||
// This means we open, close and open again, which sucks, but
|
||||
// right now it's the easiest way to get it to work. A better
|
||||
// solution will hopefully be found soon...
|
||||
if (lex->sptabs.records || lex->query_tables)
|
||||
{
|
||||
uint procs, funs, tabs;
|
||||
|
||||
if (thd->mem_root != thd->current_arena->mem_root)
|
||||
{
|
||||
thdmemroot= thd->mem_root;
|
||||
thd->mem_root= thd->current_arena->mem_root;
|
||||
}
|
||||
if (!sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
|
||||
DBUG_RETURN(TRUE);
|
||||
procs= lex->spprocs.records;
|
||||
funs= lex->spfuns.records;
|
||||
tabs= lex->sptabs.records;
|
||||
|
||||
if (((*locked_tables)= sp_hash_to_table_list(thd, &lex->sptabs)))
|
||||
{
|
||||
// We don't want these updated now
|
||||
uint ctmpdtabs= thd->status_var.created_tmp_disk_tables;
|
||||
uint ctmptabs= thd->status_var.created_tmp_tables;
|
||||
uint count;
|
||||
|
||||
thd->shortcut_make_view= TRUE;
|
||||
open_tables(thd, *locked_tables, &count);
|
||||
thd->shortcut_make_view= FALSE;
|
||||
close_thread_tables(thd);
|
||||
thd->status_var.created_tmp_disk_tables= ctmpdtabs;
|
||||
thd->status_var.created_tmp_tables= ctmptabs;
|
||||
thd->clear_error();
|
||||
mysql_reset_errors(thd);
|
||||
(*locked_tables)= NULL;
|
||||
}
|
||||
// A kludge: Decrease all temp. table's query ids to allow a
|
||||
// second opening.
|
||||
for (TABLE *table= thd->temporary_tables; table ; table=table->next)
|
||||
table->query_id-= 1;
|
||||
if (procs < lex->spprocs.records ||
|
||||
funs < lex->spfuns.records ||
|
||||
tabs < lex->sptabs.records)
|
||||
{
|
||||
if (thdmemroot)
|
||||
thd->mem_root= thdmemroot;
|
||||
continue; // Found more SPs or tabs, try again
|
||||
}
|
||||
}
|
||||
if (lex->sptabs.records &&
|
||||
(lex->spfuns.records || lex->spprocs.records) &&
|
||||
sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
|
||||
{
|
||||
if (((*locked_tables)= sp_hash_to_table_list(thd, &lex->sptabs)))
|
||||
{
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
thd->variables.innodb_table_locks= FALSE;
|
||||
#endif
|
||||
sp_open_and_lock_tables(thd, *locked_tables);
|
||||
}
|
||||
}
|
||||
if (thdmemroot)
|
||||
thd->mem_root= thdmemroot;
|
||||
}
|
||||
break;
|
||||
} // while (1)
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Perform one connection-level (COM_XXXX) command.
|
||||
@ -1752,7 +1653,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
in embedded server - just store them to be executed later
|
||||
*/
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables ||
|
||||
thd->prelocked_mode)
|
||||
close_thread_tables(thd);
|
||||
#endif
|
||||
ulong length= (ulong)(packet_end-packet);
|
||||
@ -1855,19 +1757,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
select_lex.table_list.link_in_list((byte*) &table_list,
|
||||
(byte**) &table_list.next_local);
|
||||
thd->lex->query_tables= &table_list;
|
||||
thd->shortcut_make_view= 0;
|
||||
process_nested_sp(thd, thd->lex, &locked_tables);
|
||||
|
||||
/* switch on VIEW optimisation: do not fill temporary tables */
|
||||
thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
mysqld_list_fields(thd,&table_list,fields);
|
||||
thd->lex->unit.cleanup();
|
||||
thd->cleanup_after_query();
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
release_local_lock(thd, locked_tables, old_innodb_table_locks);
|
||||
#else
|
||||
release_local_lock(thd, locked_tables, false);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -2089,7 +1984,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
|
||||
break;
|
||||
}
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables ||
|
||||
thd->prelocked_mode)
|
||||
{
|
||||
thd->proc_info="closing tables";
|
||||
close_thread_tables(thd); /* Free tables */
|
||||
@ -2334,11 +2230,7 @@ mysql_execute_command(THD *thd)
|
||||
TABLE_LIST *all_tables;
|
||||
/* most outer SELECT_LEX_UNIT of query */
|
||||
SELECT_LEX_UNIT *unit= &lex->unit;
|
||||
/* Locked closure of all tables */
|
||||
TABLE_LIST *locked_tables= NULL;
|
||||
/* Saved variable value */
|
||||
my_bool old_innodb_table_locks=
|
||||
IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
|
||||
DBUG_ENTER("mysql_execute_command");
|
||||
thd->net.no_send_error= 0;
|
||||
|
||||
@ -2361,26 +2253,14 @@ mysql_execute_command(THD *thd)
|
||||
/* should be assigned after making first tables same */
|
||||
all_tables= lex->query_tables;
|
||||
|
||||
thd->shortcut_make_view= 0;
|
||||
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
|
||||
lex->sql_command != SQLCOM_CREATE_SPFUNCTION &&
|
||||
lex->sql_command != SQLCOM_LOCK_TABLES &&
|
||||
lex->sql_command != SQLCOM_UNLOCK_TABLES)
|
||||
{
|
||||
thd->no_warnings_for_error= 1;
|
||||
res= process_nested_sp(thd, lex, &locked_tables);
|
||||
thd->no_warnings_for_error= 0;
|
||||
if (res)
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
Reset warning count for each query that uses tables
|
||||
A better approach would be to reset this for any commands
|
||||
that is not a SHOW command or a select that only access local
|
||||
variables, but for now this is probably good enough.
|
||||
*/
|
||||
if (all_tables || &lex->select_lex != lex->all_selects_list)
|
||||
if (all_tables || &lex->select_lex != lex->all_selects_list ||
|
||||
lex->spfuns.records || lex->spprocs.records)
|
||||
mysql_reset_errors(thd);
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
@ -2614,9 +2494,8 @@ mysql_execute_command(THD *thd)
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DO:
|
||||
if (all_tables &&
|
||||
(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables)))
|
||||
if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables))
|
||||
goto error;
|
||||
|
||||
res= mysql_do(thd, *lex->insert_list);
|
||||
@ -3485,8 +3364,7 @@ unsent_create_error:
|
||||
case SQLCOM_SET_OPTION:
|
||||
{
|
||||
List<set_var_base> *lex_var_list= &lex->var_list;
|
||||
if (all_tables &&
|
||||
(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables)))
|
||||
goto error;
|
||||
if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
|
||||
@ -3532,7 +3410,7 @@ unsent_create_error:
|
||||
thd->in_lock_tables=1;
|
||||
thd->options|= OPTION_TABLE_LOCK;
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, all_tables)))
|
||||
if (!(res= simple_open_n_lock_tables(thd, all_tables)))
|
||||
{
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
if (thd->variables.query_cache_wlock_invalidate)
|
||||
@ -4115,7 +3993,20 @@ unsent_create_error:
|
||||
{
|
||||
sp_head *sp;
|
||||
|
||||
if (!(sp= sp_find_procedure(thd, lex->spname)))
|
||||
/*
|
||||
This will cache all SP and SF and open and lock all tables
|
||||
required for execution.
|
||||
*/
|
||||
if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
By this moment all needed SPs should be in cache so no need
|
||||
to look into DB. Moreover we may be unable to do it becuase
|
||||
we may don't have read lock on mysql.proc
|
||||
*/
|
||||
if (!(sp= sp_find_procedure(thd, lex->spname, TRUE)))
|
||||
{
|
||||
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
|
||||
lex->spname->m_qname.str);
|
||||
@ -4130,12 +4021,6 @@ unsent_create_error:
|
||||
/* bits that should be cleared in thd->server_status */
|
||||
uint bits_to_be_cleared= 0;
|
||||
|
||||
/* In case the arguments are subselects... */
|
||||
if (all_tables &&
|
||||
(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
|
||||
open_and_lock_tables(thd, all_tables)))
|
||||
goto error;
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
my_bool nsok= thd->net.no_send_ok;
|
||||
thd->net.no_send_ok= TRUE;
|
||||
@ -4606,11 +4491,6 @@ cleanup:
|
||||
if (thd->lock == thd->locked_tables)
|
||||
thd->lock= 0;
|
||||
}
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
release_local_lock(thd, locked_tables, old_innodb_table_locks);
|
||||
#else
|
||||
release_local_lock(thd, locked_tables, false);
|
||||
#endif
|
||||
DBUG_RETURN(res || thd->net.report_error);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user