fixed SP processing for mysql_list_fields() command (BUG#6814)
sql/sql_parse.cc: SP pre/post processing moved to functions and used for mysql_list_fields command execution. tests/mysql_client_test.c: test of mysql_list_fields call for VIEW with SP function
This commit is contained in:
parent
615616b700
commit
5f0064f927
201
sql/sql_parse.cc
201
sql/sql_parse.cc
@ -1487,6 +1487,106 @@ 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.
|
||||
SYNOPSIS
|
||||
@ -1733,8 +1833,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
#else
|
||||
{
|
||||
char *fields, *pend;
|
||||
/* Locked closure of all tables */
|
||||
TABLE_LIST *locked_tables= NULL;
|
||||
TABLE_LIST table_list;
|
||||
LEX_STRING conv_name;
|
||||
/* Saved variable value */
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
my_bool old_innodb_table_locks= thd->variables.innodb_table_locks;
|
||||
#endif
|
||||
|
||||
|
||||
statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
|
||||
&LOCK_status);
|
||||
@ -1778,12 +1885,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
thd->lex->
|
||||
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();
|
||||
release_local_lock(thd, locked_tables, old_innodb_table_locks);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -2268,85 +2379,8 @@ mysql_execute_command(THD *thd)
|
||||
lex->sql_command != SQLCOM_LOCK_TABLES &&
|
||||
lex->sql_command != SQLCOM_UNLOCK_TABLES)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
|
||||
DBUG_RETURN(-1);
|
||||
if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
|
||||
DBUG_RETURN(-1);
|
||||
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(-1);
|
||||
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)
|
||||
if (process_nested_sp(thd, lex, &locked_tables))
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4362,14 +4396,7 @@ cleanup:
|
||||
thd->lock= 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
release_local_lock(thd, locked_tables, old_innodb_table_locks);
|
||||
DBUG_RETURN(res || thd->net.report_error);
|
||||
}
|
||||
|
||||
|
@ -12584,6 +12584,42 @@ static void test_bug7990()
|
||||
}
|
||||
|
||||
|
||||
static void test_view_sp_list_fields()
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
int rc;
|
||||
MYSQL_RES *res;
|
||||
|
||||
myheader("test_view_insert_fields");
|
||||
|
||||
rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS v1, t1, t2");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1, t1, t2");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "create function f1 () returns int return 5");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "create table t1 (s1 char,s2 char)");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "create table t2 (s1 int);");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "create view v1 as select s2,sum(s1) - \
|
||||
count(s2) as vx from t1 group by s2 having sum(s1) - count(s2) < (select f1() \
|
||||
from t2);");
|
||||
myquery(rc);
|
||||
res= mysql_list_fields(mysql, "v1", NullS);
|
||||
DIE_UNLESS(res != 0 && mysql_num_fields(res) != 0);
|
||||
rc= mysql_query(mysql, "DROP FUNCTION f1");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "DROP VIEW v1");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "DROP TABLE t1, t2");
|
||||
myquery(rc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read and parse arguments and MySQL options from my.cnf
|
||||
*/
|
||||
@ -12645,6 +12681,7 @@ and you are welcome to modify and redistribute it under the GPL license\n");
|
||||
|
||||
|
||||
static struct my_tests_st my_tests[]= {
|
||||
{ "test_view_sp_list_fields", test_view_sp_list_fields},
|
||||
{ "client_query", client_query },
|
||||
{ "test_prepare_insert_update", test_prepare_insert_update},
|
||||
#if NOT_YET_WORKING
|
||||
|
Loading…
x
Reference in New Issue
Block a user