diff options
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r-- | sql/sql_lex.cc | 131 |
1 files changed, 96 insertions, 35 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f3dfd95815e..a9d542756fb 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -25,8 +25,8 @@ #include "item_create.h" #include <m_ctype.h> #include <hash.h> -#include "sp.h" #include "sp_head.h" +#include "sp.h" #include "sql_select.h" static int lex_one_token(void *arg, void *yythd); @@ -503,6 +503,7 @@ void lex_start(THD *thd) lex->event_parse_data= NULL; lex->profile_options= PROFILE_NONE; lex->nest_level=0 ; + lex->select_lex.nest_level_base= &lex->unit; lex->allow_sum_func= 0; lex->in_sum_func= NULL; /* @@ -1499,39 +1500,39 @@ int lex_one_token(void *arg, void *yythd) lip->save_in_comment_state(); + if (lip->yyPeekn(2) == 'M' && lip->yyPeekn(3) == '!') + { + /* Skip MariaDB unique marker */ + lip->set_echo(FALSE); + lip->yySkip(); + /* The following if will be true */ + } if (lip->yyPeekn(2) == '!') { lip->in_comment= DISCARD_COMMENT; /* Accept '/' '*' '!', but do not keep this marker. */ lip->set_echo(FALSE); - lip->yySkip(); - lip->yySkip(); - lip->yySkip(); + lip->yySkipn(3); /* The special comment format is very strict: - '/' '*' '!', followed by exactly + '/' '*' '!', followed by an optional 'M' and exactly 1 digit (major), 2 digits (minor), then 2 digits (dot). 32302 -> 3.23.02 50032 -> 5.0.32 50114 -> 5.1.14 */ - char version_str[6]; - version_str[0]= lip->yyPeekn(0); - version_str[1]= lip->yyPeekn(1); - version_str[2]= lip->yyPeekn(2); - version_str[3]= lip->yyPeekn(3); - version_str[4]= lip->yyPeekn(4); - version_str[5]= 0; - if ( my_isdigit(cs, version_str[0]) - && my_isdigit(cs, version_str[1]) - && my_isdigit(cs, version_str[2]) - && my_isdigit(cs, version_str[3]) - && my_isdigit(cs, version_str[4]) + if ( my_isdigit(cs, lip->yyPeekn(0)) + && my_isdigit(cs, lip->yyPeekn(1)) + && my_isdigit(cs, lip->yyPeekn(2)) + && my_isdigit(cs, lip->yyPeekn(3)) + && my_isdigit(cs, lip->yyPeekn(4)) ) { ulong version; - version=strtol(version_str, NULL, 10); + char *end_ptr= (char*) lip->get_ptr()+5; + int error; + version= (ulong) my_strtoll10(lip->get_ptr(), &end_ptr, &error); if (version <= MYSQL_VERSION_ID) { @@ -3455,18 +3456,19 @@ void st_select_lex::append_table_to_list(TABLE_LIST *TABLE_LIST::*link, tl->*link= table; } + /* @brief - Remove given table from the leaf_tables list. + Replace given table from the leaf_tables list for a list of tables - @param link Offset to which list in table structure to use - @param table Table to remove + @param table Table to replace + @param list List to substititute the table for @details - Remove 'table' from the leaf_tables list using the 'link' offset. + Replace 'table' from the leaf_tables list for a list of tables 'tbl_list'. */ -void st_select_lex::remove_table_from_list(TABLE_LIST *table) +void st_select_lex::replace_leaf_table(TABLE_LIST *table, List<TABLE_LIST> &tbl_list) { TABLE_LIST *tl; List_iterator<TABLE_LIST> ti(leaf_tables); @@ -3474,7 +3476,7 @@ void st_select_lex::remove_table_from_list(TABLE_LIST *table) { if (tl == table) { - ti.remove(); + ti.replace(tbl_list); break; } } @@ -3579,8 +3581,6 @@ bool SELECT_LEX::merge_subquery(THD *thd, TABLE_LIST *derived, uint table_no, table_map map) { derived->wrap_into_nested_join(subq_select->top_join_list); - /* Reconnect the next_leaf chain. */ - leaf_tables.concat(&subq_select->leaf_tables); ftfunc_list->concat(subq_select->ftfunc_list); if (join || @@ -3596,18 +3596,14 @@ bool SELECT_LEX::merge_subquery(THD *thd, TABLE_LIST *derived, in_subq->emb_on_expr_nest= derived; } } - /* - Remove merged table from chain. - When merge_subquery is called at a subquery-to-semijoin transformation - the derived isn't in the leaf_tables list, so in this case the call of - remove_table_from_list does not cause any actions. - */ - remove_table_from_list(derived); /* Walk through child's tables and adjust table map, tablenr, * parent_lex */ subq_select->remap_tables(derived, map, table_no, this); subq_select->merged_into= this; + + replace_leaf_table(derived, subq_select->leaf_tables); + return FALSE; } @@ -3648,10 +3644,33 @@ void SELECT_LEX::update_used_tables() { TABLE_LIST *tl; List_iterator<TABLE_LIST> ti(leaf_tables); + while ((tl= ti++)) { - TABLE_LIST *embedding; - embedding= tl; + if (tl->table && !tl->is_view_or_derived()) + { + TABLE_LIST *embedding= tl->embedding; + for (embedding= tl->embedding; embedding; embedding=embedding->embedding) + { + if (embedding->is_view_or_derived()) + { + DBUG_ASSERT(embedding->is_merged_derived()); + TABLE *tab= tl->table; + tab->covering_keys= tab->s->keys_for_keyread; + tab->covering_keys.intersect(tab->keys_in_use_for_query); + tab->merge_keys.clear_all(); + bitmap_clear_all(tab->read_set); + bitmap_clear_all(tab->vcol_set); + break; + } + } + } + } + + ti.rewind(); + while ((tl= ti++)) + { + TABLE_LIST *embedding= tl; do { bool maybe_null; @@ -3680,6 +3699,7 @@ void SELECT_LEX::update_used_tables() embedding= tl->embedding; } } + if (join->conds) { join->conds->update_used_tables(); @@ -3862,6 +3882,47 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd) } +/* + Return true if this select_lex has been converted into a semi-join nest + within 'ancestor'. + + We need a loop to check this because there could be several nested + subselects, like + + SELECT ... FROM grand_parent + WHERE expr1 IN (SELECT ... FROM parent + WHERE expr2 IN ( SELECT ... FROM child) + + which were converted into: + + SELECT ... + FROM grand_parent SEMI_JOIN (parent JOIN child) + WHERE + expr1 AND expr2 + + In this case, both parent and child selects were merged into the parent. +*/ + +bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) +{ + bool all_merged= TRUE; + for (SELECT_LEX *sl= this; sl && sl!=ancestor; + sl=sl->outer_select()) + { + Item *subs= sl->master_unit()->item; + if (subs && subs->type() == Item::SUBSELECT_ITEM && + ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && + ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN)) + { + continue; + } + all_merged= FALSE; + break; + } + return all_merged; +} + + /** A routine used by the parser to decide whether we are specifying a full partitioning or if only partitions to add or to split. |