1
0
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:
dlenev@mysql.com
2005-03-04 17:46:45 +03:00
29 changed files with 1818 additions and 920 deletions

View File

@ -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);
}