--- a/sql/sql_view.cc Thu Mar 22 20:12:41 2007 +++ b/sql/sql_view.cc Mon Apr 16 00:57:52 2007 @@ -1177,8 +1177,9 @@ - VIEW SELECT allow merging - VIEW used in subquery or command support MERGE algorithm */ + SELECT_LEX *table_select_lex= table->select_lex; if (view_is_mergeable && - (table->select_lex->master_unit() != &old_lex->unit || + (table_select_lex->master_unit() != &old_lex->unit || old_lex->can_use_merged()) && !old_lex->can_not_use_merged()) { @@ -1201,9 +1202,9 @@ /* prepare view context */ lex->select_lex.context.resolve_in_table_list_only(view_main_select_tables); lex->select_lex.context.outer_context= 0; - lex->select_lex.context.select_lex= table->select_lex; + lex->select_lex.context.select_lex= table_select_lex; lex->select_lex.select_n_having_items+= - table->select_lex->select_n_having_items; + table_select_lex->select_n_having_items; /* Tables of the main select of the view should be marked as belonging @@ -1212,7 +1213,7 @@ with unions). */ for (tbl= lex->select_lex.get_table_list(); tbl; tbl= tbl->next_local) - tbl->select_lex= table->select_lex; + tbl->select_lex= table_select_lex; { if (view_main_select_tables->next_local) @@ -1249,7 +1250,7 @@ NOTE: we do not support UNION here, so we take only one select */ - SELECT_LEX_NODE *end_unit= table->select_lex->slave; + SELECT_LEX_NODE *end_unit= table_select_lex->slave; SELECT_LEX_UNIT *next_unit; for (SELECT_LEX_UNIT *unit= lex->select_lex.first_inner_unit(); unit; @@ -1259,17 +1260,51 @@ break; SELECT_LEX_NODE *save_slave= unit->slave; next_unit= unit->next_unit(); - unit->include_down(table->select_lex); + unit->include_down(table_select_lex); unit->slave= save_slave; // fix include_down initialisation } + if (table_select_lex->linkage == UNION_TYPE + && table_select_lex->master_unit()->global_parameters == table_select_lex) + { + /* + Special case, if the view is used in an outer union, we must take care + not to push the order by conditions to the union. + If this is the last part of the outer union and if it was not contained + in braces, then global_parameters will point to this select_lex. + We can simply point them to the fake_select_lex, which exists for every + union + */ + DBUG_ASSERT(table_select_lex->master_unit()->fake_select_lex); + table_select_lex->master_unit()->global_parameters= + table_select_lex->master_unit()->fake_select_lex; + + /* + Any existing "order by" and "limit" belongs to the union. + Since global_parameters pointed to this select_lex, this is + the last part of the union + */ + SELECT_LEX *global_lex= table_select_lex->master_unit()->global_parameters; + global_lex->order_list.push_back(&table_select_lex->order_list); + table_select_lex->init_order(); // will empty the list + global_lex->select_limit= table_select_lex->select_limit; + global_lex->offset_limit= table_select_lex->offset_limit; + global_lex->explicit_limit= table_select_lex->explicit_limit; + table_select_lex->select_limit= 0; + table_select_lex->offset_limit= 0; + table_select_lex->explicit_limit= 0; + + // braces = true allows the union to ignore the order by, if no limit exists. + table_select_lex->set_braces(TRUE); + } + table_select_lex->order_list.push_back(&lex->select_lex.order_list); + /* - This SELECT_LEX will be linked in global SELECT_LEX list - to make it processed by mysql_handle_derived(), - but it will not be included to SELECT_LEX tree, because it - will not be executed + This SELECT_LEX will be linked in global SELECT_LEX list + to make it processed by mysql_handle_derived(), + but it will not be included to SELECT_LEX tree, because it + will not be executed */ - table->select_lex->order_list.push_back(&lex->select_lex.order_list); goto ok; } --- a/mysql-test/t/view.test Thu Mar 8 17:42:33 2007 +++ b/mysql-test/t/view.test Mon Apr 16 01:10:49 2007 @@ -3204,3 +3204,87 @@ DROP table t1,t2; --echo End of 5.0 tests. + +# +#BUG#27786 Select from a view as part of a union could cause errors +# +# An "order by" of the view could incorrectly apply to the UNION +# if the view was not in braces +# + +create table t1 (a int); +insert into t1 values (10), (20), (20), (30); +create table t2 (a int); +insert into t2 values (5), (50); +create table t3 (a int); +insert into t3 values (10), (50); + +create view v1 as select a from t1 order by a; +create view v2 as select a from t1 order by a desc; +create view v3 as select a from t1 order by a limit 2; +create view v4 as select a from t1 order by a desc limit 2; + +select a from t2 UNION select * from v1; +select a from t2 UNION select * from v1 order by 1; +select a from t2 UNION select * from v1 order by a desc; +select a from t2 UNION select * from v1 order by a limit 2; +select a from t2 UNION select * from v1 order by 1 desc limit 2; +# "group by" still applies to the view +# 10 is NOT grouped +select a from t3 UNION ALL select * from v1; +select a from t3 UNION ALL select * from v1 group by a; +select a from t3 UNION ALL select * from v1 group by a order by 1; + +select * from v1 UNION select a from t2; +select * from v1 UNION select a from t2 order by 1; +select * from v1 UNION select a from t2 order by a desc; +select * from v1 UNION select a from t2 order by a limit 2; +select * from v1 UNION select a from t2 order by 1 desc limit 2; + +select * from v1 UNION select a from v1; +select * from v1 UNION select a from v1 order by 1; +select * from v1 UNION select a from v1 order by a desc; +select * from v1 UNION select a from v1 order by a limit 2; +select * from v1 UNION select a from v1 order by 1 desc limit 2; + + +select a from t2 UNION select * from v2 order by 1; +select a from t2 UNION select * from v2 order by a desc; +select a from t2 UNION select * from v2 order by a limit 2; +select a from t2 UNION select * from v2 order by 1 desc limit 2; + +select a from t3 UNION ALL select * from v2 order by 1; +select a from t3 UNION ALL select * from v2 group by a order by 1; +select a from t3 UNION ALL select * from v2 group by a order by a desc; + +select * from v2 UNION select a from v2 order by 1; +select * from v2 UNION select a from v2 order by a desc; +select * from v2 UNION select a from v2 order by a limit 2; +select * from v2 UNION select a from v2 order by 1 desc limit 2; + + +select a from t2 UNION select * from v3 order by 1; +select a from t2 UNION select * from v3 order by a desc; +select a from t2 UNION select * from v3 order by a limit 2; +select a from t2 UNION select * from v3 order by 1 desc limit 2; + +select * from v3 UNION select a from v3 order by 1; +select * from v3 UNION select a from v3 order by a desc; +select * from v3 UNION select a from v3 order by a limit 2; +select * from v3 UNION select a from v3 order by 1 desc limit 2; + + +select a from t2 UNION select * from v4 order by 1; +select a from t2 UNION select * from v4 order by a desc; +select a from t2 UNION select * from v4 order by a limit 2; +select a from t2 UNION select * from v4 order by 1 desc limit 2; + +select * from v4 UNION select a from v4 order by 1; +select * from v4 UNION select a from v4 order by a desc; +select * from v4 UNION select a from v4 order by a limit 2; +select * from v4 UNION select a from v4 order by 1 desc limit 2; + + + +drop table t1,t2,t3; +drop view v1,v2,v3,v4; --- a/mysql-test/r/view.result Fri Mar 9 09:37:05 2007 +++ b/mysql-test/r/view.result Mon Apr 16 01:11:03 2007 @@ -3310,3 +3310,252 @@ DROP VIEW v1; DROP table t1,t2; End of 5.0 tests. +create table t1 (a int); +insert into t1 values (10), (20), (20), (30); +create table t2 (a int); +insert into t2 values (5), (50); +create table t3 (a int); +insert into t3 values (10), (50); +create view v1 as select a from t1 order by a; +create view v2 as select a from t1 order by a desc; +create view v3 as select a from t1 order by a limit 2; +create view v4 as select a from t1 order by a desc limit 2; +select a from t2 UNION select * from v1; +a +5 +50 +10 +20 +30 +select a from t2 UNION select * from v1 order by 1; +a +5 +10 +20 +30 +50 +select a from t2 UNION select * from v1 order by a desc; +a +50 +30 +20 +10 +5 +select a from t2 UNION select * from v1 order by a limit 2; +a +5 +10 +select a from t2 UNION select * from v1 order by 1 desc limit 2; +a +50 +30 +select a from t3 UNION ALL select * from v1; +a +10 +50 +10 +20 +20 +30 +select a from t3 UNION ALL select * from v1 group by a; +a +10 +50 +10 +20 +30 +select a from t3 UNION ALL select * from v1 group by a order by 1; +a +10 +10 +20 +30 +50 +select * from v1 UNION select a from t2; +a +10 +20 +30 +5 +50 +select * from v1 UNION select a from t2 order by 1; +a +5 +10 +20 +30 +50 +select * from v1 UNION select a from t2 order by a desc; +a +50 +30 +20 +10 +5 +select * from v1 UNION select a from t2 order by a limit 2; +a +5 +10 +select * from v1 UNION select a from t2 order by 1 desc limit 2; +a +50 +30 +select * from v1 UNION select a from v1; +a +10 +20 +30 +select * from v1 UNION select a from v1 order by 1; +a +10 +20 +30 +select * from v1 UNION select a from v1 order by a desc; +a +30 +20 +10 +select * from v1 UNION select a from v1 order by a limit 2; +a +10 +20 +select * from v1 UNION select a from v1 order by 1 desc limit 2; +a +30 +20 +select a from t2 UNION select * from v2 order by 1; +a +5 +10 +20 +30 +50 +select a from t2 UNION select * from v2 order by a desc; +a +50 +30 +20 +10 +5 +select a from t2 UNION select * from v2 order by a limit 2; +a +5 +10 +select a from t2 UNION select * from v2 order by 1 desc limit 2; +a +50 +30 +select a from t3 UNION ALL select * from v2 order by 1; +a +10 +10 +20 +20 +30 +50 +select a from t3 UNION ALL select * from v2 group by a order by 1; +a +10 +10 +20 +30 +50 +select a from t3 UNION ALL select * from v2 group by a order by a desc; +a +50 +30 +20 +10 +10 +select * from v2 UNION select a from v2 order by 1; +a +10 +20 +30 +select * from v2 UNION select a from v2 order by a desc; +a +30 +20 +10 +select * from v2 UNION select a from v2 order by a limit 2; +a +10 +20 +select * from v2 UNION select a from v2 order by 1 desc limit 2; +a +30 +20 +select a from t2 UNION select * from v3 order by 1; +a +5 +10 +20 +50 +select a from t2 UNION select * from v3 order by a desc; +a +50 +20 +10 +5 +select a from t2 UNION select * from v3 order by a limit 2; +a +5 +10 +select a from t2 UNION select * from v3 order by 1 desc limit 2; +a +50 +20 +select * from v3 UNION select a from v3 order by 1; +a +10 +20 +select * from v3 UNION select a from v3 order by a desc; +a +20 +10 +select * from v3 UNION select a from v3 order by a limit 2; +a +10 +20 +select * from v3 UNION select a from v3 order by 1 desc limit 2; +a +20 +10 +select a from t2 UNION select * from v4 order by 1; +a +5 +20 +30 +50 +select a from t2 UNION select * from v4 order by a desc; +a +50 +30 +20 +5 +select a from t2 UNION select * from v4 order by a limit 2; +a +5 +20 +select a from t2 UNION select * from v4 order by 1 desc limit 2; +a +50 +30 +select * from v4 UNION select a from v4 order by 1; +a +20 +30 +select * from v4 UNION select a from v4 order by a desc; +a +30 +20 +select * from v4 UNION select a from v4 order by a limit 2; +a +20 +30 +select * from v4 UNION select a from v4 order by 1 desc limit 2; +a +30 +20 +drop table t1,t2,t3; +drop view v1,v2,v3,v4;