diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b30cf450d6d..bb99d20b305 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -326,23 +326,19 @@ bool Item_subselect::set_fake_select_as_master_processor(uchar *arg) /* Move the st_select_lex_unit of a subquery from a global ORDER BY clause to become a direct child of the fake_select of a UNION. In this way the - ORDER BY is applied to the temporary table that contains the result of the - whole UNION, and all columns in the subquery are resolved against this table. - - Apply the transformation only for immediate child subqueries of a - UNION query. + ORDER BY that is applied to the temporary table that contains the result of + the whole UNION, and all columns in the subquery are resolved against this + table. The transformation is applied only for immediate child subqueries of + a UNION query. */ if (unit->outer_select()->master_unit()->fake_select_lex == fake_select) { /* - Set the master of the subquery to be the fake select (i.e. the whole UNION), - instead of the last query in the UNION. - TODO: - This is a hack, instead we should call: unit->include_down(fake_select); - However, this call results in an infinite loop where - some_select_lex->master == some_select_lex. + Set the master of the subquery to be the fake select (i.e. the whole + UNION), instead of the last query in the UNION. */ - unit->set_master(fake_select); + fake_select->add_slave(unit); + DBUG_ASSERT(unit->outer_select() == fake_select); /* Adjust the name resolution context hierarchy accordingly. */ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) sl->context.outer_context= &(fake_select->context); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e8a724cea82..f7e2f1835ad 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1684,6 +1684,31 @@ void st_select_lex_node::include_down(st_select_lex_node *upper) slave= 0; } + +void st_select_lex_node::add_slave(st_select_lex_node *slave_arg) +{ + for (; slave; slave= slave->next) + if (slave == slave_arg) + return; + + if (slave) + { + st_select_lex_node *slave_arg_slave= slave_arg->slave; + /* Insert in the front of list of slaves if any. */ + slave_arg->include_neighbour(slave); + /* include_neighbour() sets slave_arg->slave=0, restore it. */ + slave_arg->slave= slave_arg_slave; + /* Count on include_neighbour() setting the master. */ + DBUG_ASSERT(slave_arg->master == this); + } + else + { + slave= slave_arg; + slave_arg->master= this; + } +} + + /* include on level down (but do not link) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 525d7c5cf46..eb5a7acbbd2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -439,10 +439,10 @@ public: st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {} virtual ~st_select_lex_node() {} inline st_select_lex_node* get_master() { return master; } - inline void set_master(st_select_lex_node* master_arg) { master= master_arg; } virtual void init_query(); virtual void init_select(); void include_down(st_select_lex_node *upper); + void add_slave(st_select_lex_node *slave_arg); void include_neighbour(st_select_lex_node *before); void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref); void include_global(st_select_lex_node **plink);