summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2017-10-11 08:37:35 -0700
committerIgor Babaev <igor@askmonty.org>2017-10-11 10:22:46 -0700
commit4c9d19ee657b882fcb5a2daea702357a1a73b55f (patch)
tree5aadbb1ed36644efd04754f62cc738ba17f10ab9 /sql
parentdc8ac122bb484b1e88c0aafee3e961208b93bbb5 (diff)
downloadmariadb-git-4c9d19ee657b882fcb5a2daea702357a1a73b55f.tar.gz
Fixed the bug mdev-13796.
A reference to a CTE may occur not in the master of the CTE specification. In this case if the reference to the CTE is the first one the specification should be detached from its master and attached to the referencing select. Also fixed the TYPE column in the lines of the EXPLAIN output created for CTE tables.
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_cte.cc10
-rw-r--r--sql/sql_lex.cc27
-rw-r--r--sql/sql_lex.h1
3 files changed, 36 insertions, 2 deletions
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index 1b14c5b68b7..e1af30123f6 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -991,7 +991,7 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table)
been done yet.
*/
if (with_elem && sl->master_unit() == with_elem->spec)
- break;
+ break;
With_clause *with_clause=sl->get_with_clause();
if (with_clause)
{
@@ -1039,13 +1039,21 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem)
}
with= with_elem;
if (!with_elem->is_referenced() || with_elem->is_recursive)
+ {
derived= with_elem->spec;
+ if (derived->get_master() != select_lex &&
+ !is_with_table_recursive_reference())
+ {
+ derived->move_as_slave(select_lex);
+ }
+ }
else
{
if(!(derived= with_elem->clone_parsed_spec(thd, this)))
return true;
derived->with_element= with_elem;
}
+ derived->first_select()->linkage= DERIVED_TABLE_TYPE;
with_elem->inc_references();
return false;
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 7879edc3f67..c8474c66ca1 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2304,6 +2304,30 @@ st_select_lex_node *st_select_lex_node:: insert_chain_before(
return this;
}
+
+/*
+ Detach the node from its master and attach it to a new master
+*/
+
+void st_select_lex_node::move_as_slave(st_select_lex_node *new_master)
+{
+ exclude_from_tree();
+ if (new_master->slave)
+ {
+ st_select_lex_node *curr= new_master->slave;
+ for ( ; curr->next ; curr= curr->next) ;
+ prev= &curr->next;
+ }
+ else
+ {
+ prev= &new_master->slave;
+ new_master->slave= this;
+ }
+ next= 0;
+ master= new_master;
+}
+
+
/*
Exclude a node from the tree lex structure, but leave it in the global
list of nodes.
@@ -4404,7 +4428,8 @@ void st_select_lex::set_explain_type(bool on_the_fly)
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
*/
if (tab->table && tab->table->pos_in_table_list &&
- tab->table->pos_in_table_list->with)
+ tab->table->pos_in_table_list->with &&
+ tab->table->pos_in_table_list->with->is_recursive)
{
uses_cte= true;
break;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a1ef42861b4..9ab09c9fe7e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -561,6 +561,7 @@ public:
}
st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert,
st_select_lex_node *end_chain_node);
+ void move_as_slave(st_select_lex_node *new_master);
friend class st_select_lex_unit;
friend bool mysql_new_select(LEX *lex, bool move_down);
friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,