summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/sql_parse.cc201
-rw-r--r--tests/mysql_client_test.c37
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