summaryrefslogtreecommitdiff
path: root/sql/sql_lex.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r--sql/sql_lex.cc131
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.