summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc108
1 files changed, 99 insertions, 9 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9977eaad0ff..8166a156b8c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1254,7 +1254,7 @@ mysql_execute_command(void)
THD *thd= current_thd;
LEX *lex= &thd->lex;
TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
- SELECT_LEX *select_lex= lex->select;
+ SELECT_LEX *select_lex= &lex->select_lex;
SELECT_LEX_UNIT *unit= &lex->unit;
DBUG_ENTER("mysql_execute_command");
@@ -1281,18 +1281,69 @@ mysql_execute_command(void)
#endif
}
+ select_result *explain_result= 0;
/*
- Skip if we are in the slave thread, some table rules have been given
- and the table list says the query should not be replicated
+ TODO: make derived tables processing 'inside' SELECT processing.
+ TODO: solve problem with depended derived tables in subselects
*/
- if (lex->derived_tables)
+ if (lex->sql_command == SQLCOM_SELECT &&
+ (select_lex->options & SELECT_DESCRIBE) &&
+ lex->derived_tables)
+ {
+ if (!(explain_result= new select_send()))
+ {
+ send_error(&thd->net, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
+ }
+ //check rights
+ for (TABLE_LIST *cursor= tables;
+ cursor;
+ cursor= cursor->next)
+ if (cursor->derived)
+ {
+ TABLE_LIST *tables=
+ (TABLE_LIST *)((SELECT_LEX_UNIT *)
+ cursor->derived)->first_select()->table_list.first;
+ int res;
+ if (tables)
+ res= check_table_access(thd,SELECT_ACL, tables);
+ else
+ res= check_access(thd, SELECT_ACL, any_db);
+ if (res)
+ DBUG_VOID_RETURN;
+ }
+ thd->send_explain_fields(explain_result);
+ // EXPLAIN derived tables
+ for (TABLE_LIST *cursor= tables;
+ cursor;
+ cursor= cursor->next)
+ if (cursor->derived)
+ {
+ SELECT_LEX *select_lex= ((SELECT_LEX_UNIT *)
+ cursor->derived)->first_select();
+ if (!open_and_lock_tables(thd,
+ (TABLE_LIST*) select_lex->table_list.first))
+ {
+ mysql_explain_select(thd, select_lex,
+ "DERIVED", explain_result);
+ // execute derived table SELECT to provide table for other SELECTs
+ if (mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived,
+ cursor, 1))
+ DBUG_VOID_RETURN;
+ }
+ else
+ DBUG_VOID_RETURN;
+ }
+
+ }
+ else if (lex->derived_tables)
{
for (TABLE_LIST *cursor= tables;
cursor;
cursor= cursor->next)
if (cursor->derived && mysql_derived(thd, lex,
(SELECT_LEX_UNIT *)cursor->derived,
- cursor))
+ cursor, 0))
DBUG_VOID_RETURN;
}
if ((lex->select_lex.next_select_in_list() &&
@@ -1374,8 +1425,44 @@ mysql_execute_command(void)
if (!(res=open_and_lock_tables(thd,tables)))
{
- query_cache_store_query(thd, tables);
- res=handle_select(thd, lex, result);
+ if (select_lex->options & SELECT_DESCRIBE)
+ {
+ delete result; // we do not need it for explain
+ if (!explain_result)
+ if (!(explain_result= new select_send()))
+ {
+ send_error(&thd->net, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
+ }
+ else
+ thd->send_explain_fields(explain_result);
+ fix_tables_pointers(select_lex);
+ for ( SELECT_LEX *sl= select_lex;
+ sl && res == 0;
+ sl= sl->next_select_in_list())
+ {
+ SELECT_LEX *first= sl->master_unit()->first_select();
+ res= mysql_explain_select(thd, sl,
+ ((select_lex==sl)?"FIRST":
+ ((sl == first)?
+ ((sl->depended)?"DEPENDENT SUBSELECT":
+ "SUBSELECT"):
+ ((sl->depended)?"DEPENDENT UNION":
+ "UNION"))),
+ explain_result);
+ }
+ if (res > 0)
+ res= -res; // mysql_explain_select do not report error
+ MYSQL_LOCK *save_lock= thd->lock;
+ thd->lock= (MYSQL_LOCK *)0;
+ explain_result->send_eof();
+ thd->lock= save_lock;
+ }
+ else
+ {
+ query_cache_store_query(thd, tables);
+ res=handle_select(thd, lex, result);
+ }
}
else
delete result;
@@ -1866,7 +1953,7 @@ mysql_execute_command(void)
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
- result, unit, 0);
+ result, unit, select_lex, 0);
delete result;
}
else
@@ -2037,7 +2124,7 @@ mysql_execute_command(void)
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
- result, unit, 0);
+ result, unit, select_lex, 0);
delete result;
}
else
@@ -2803,6 +2890,7 @@ mysql_init_query(THD *thd)
thd->lex.unit.global_parameters= &thd->lex.select_lex; //Global limit & order
thd->lex.select_lex.master= &thd->lex.unit;
thd->lex.select_lex.prev= &thd->lex.unit.slave;
+ thd->select_number= thd->lex.select_lex.select_number= 1;
thd->lex.value_list.empty();
thd->free_list= 0;
thd->lex.union_option= 0;
@@ -2832,6 +2920,7 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
+ select_lex->select_number= ++lex->thd->select_number;
if (!select_lex)
return 1;
select_lex->init_query();
@@ -2874,6 +2963,7 @@ mysql_parse(THD *thd, char *inBuf, uint length)
mysql_init_query(thd);
thd->query_length = length;
+ thd->lex.derived_tables= false;
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
LEX *lex=lex_start(thd, (uchar*) inBuf, length);