diff options
-rw-r--r-- | sql/sql_parse.cc | 201 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 37 |
2 files changed, 151 insertions, 87 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6a85fa64e18..a7a09e2c33e 100644 --- a/sql/sql_parse.cc +++ b/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); } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 0581679a845..1e117954e93 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -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 |