From 8e8363bb7540a5281c3fbc5a7cec37d9d8f35bd2 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 13 Dec 2017 18:03:38 +0300 Subject: [PATCH] SQL: VIEW system fields propagation removed [fixes #393] --- mysql-test/suite/versioning/r/derived.result | 4 - mysql-test/suite/versioning/r/view.result | 22 ++-- mysql-test/suite/versioning/t/derived.test | 2 - mysql-test/suite/versioning/t/view.test | 11 +- sql/sql_derived.cc | 15 ++- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 2 +- sql/sql_select.cc | 41 ++---- sql/sql_view.cc | 130 ------------------- sql/sql_yacc.yy | 3 +- sql/table.h | 13 +- 11 files changed, 48 insertions(+), 197 deletions(-) diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result index bc1176da17578..138f43fa4bd88 100644 --- a/mysql-test/suite/versioning/r/derived.result +++ b/mysql-test/suite/versioning/r/derived.result @@ -178,10 +178,6 @@ x select * from (select * from vt1, t2) as s0; x y 1 10 -# leading table selection -select * from (select *, vt1.sys_trx_end from t2, vt1) as s0; -y x -10 1 ### SYSTEM_TIME clash select * from (select * from t1 for system_time all) dt0 for system_time all; ERROR HY000: SYSTEM_TIME is not allowed outside historical `dt0` diff --git a/mysql-test/suite/versioning/r/view.result b/mysql-test/suite/versioning/r/view.result index 03c8b08ce2f0c..128c849b18c62 100644 --- a/mysql-test/suite/versioning/r/view.result +++ b/mysql-test/suite/versioning/r/view.result @@ -17,7 +17,7 @@ x create or replace view vt1 as select * from t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `x` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci drop view vt1; drop view vt2; create or replace view vt1 as select * from t1 for system_time all; @@ -69,7 +69,7 @@ create or replace table t1 (x int) with system versioning; create or replace view vt1(c) as select x from t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `c`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`x` AS `c` from `t1` FOR SYSTEM_TIME ALL where `t1`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci # VIEW over JOIN of versioned tables [#153] create or replace table t1 (a int) with system versioning; create or replace table t2 (b int) with system versioning; @@ -83,29 +83,29 @@ create or replace view vt12 as select * from t1 for system_time as of timestamp select * from vt12; a b # VIEW improvements [#183] -create or replace view vt1 as select a, t1.sys_trx_start, t2.sys_trx_end from t1, t2; -ERROR HY000: Creating VIEW `vt1` is prohibited: system fields from multiple tables `t1`, `t2` in query! -create or replace view vt1 as select a, t1.sys_trx_end, t2.sys_trx_end from t1, t2; -ERROR HY000: Creating VIEW `vt1` is prohibited: multiple end system fields `t1.sys_trx_end`, `t2.sys_trx_end` in query! create or replace table t3 (x int); create or replace view vt1 as select * from t1, t2, t3; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x`,`t1`.`sys_trx_start` AS `sys_trx_start`,`t1`.`sys_trx_end` AS `sys_trx_end` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = MAX_RESULT and `t2`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`b` AS `b`,`t3`.`x` AS `x` from ((`t1` FOR SYSTEM_TIME ALL join `t2` FOR SYSTEM_TIME ALL) join `t3`) where `t1`.`sys_trx_end` = MAX_RESULT and `t2`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci create or replace view vt1 as select * from t3, t2, t1; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a`,`t2`.`sys_trx_start` AS `sys_trx_start`,`t2`.`sys_trx_end` AS `sys_trx_end` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = MAX_RESULT and `t1`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t3`.`x` AS `x`,`t2`.`b` AS `b`,`t1`.`a` AS `a` from ((`t3` join `t2` FOR SYSTEM_TIME ALL) join `t1` FOR SYSTEM_TIME ALL) where `t2`.`sys_trx_end` = MAX_RESULT and `t1`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci create or replace view vt1 as select a, t2.sys_trx_end as endo from t3, t1, t2; show create view vt1; View Create View character_set_client collation_connection -vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo`,`t2`.`sys_trx_start` AS `sys_trx_start` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = MAX_RESULT and `t2`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci +vt1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vt1` AS select `t1`.`a` AS `a`,`t2`.`sys_trx_end` AS `endo` from ((`t3` join `t1` FOR SYSTEM_TIME ALL) join `t2` FOR SYSTEM_TIME ALL) where `t1`.`sys_trx_end` = MAX_RESULT and `t2`.`sys_trx_end` = MAX_RESULT latin1 latin1_swedish_ci # VIEW over UNION [#269] create or replace view vt1 as select * from t1 union select * from t1; select * from vt1; a 1 -create or replace view vvt1 as select * from t1, t2, vt1; -ERROR HY000: Creating VIEW `vvt1` is prohibited: versioned VIEW `vt1` in query! +# VIEW over UNION with non-versioned [#393] +create or replace table t2 (a int); +create or replace view vt1 as select * from t1 union select * from t2; +select * from vt1; +a +1 drop database test; create database test; diff --git a/mysql-test/suite/versioning/t/derived.test b/mysql-test/suite/versioning/t/derived.test index 590f4bc9292eb..3ef57aef1a86e 100644 --- a/mysql-test/suite/versioning/t/derived.test +++ b/mysql-test/suite/versioning/t/derived.test @@ -125,8 +125,6 @@ create view vt2 as select * from t1; select * from vt1; --echo # SYSTEM_TIME propagation from inner to outer select * from (select * from vt1, t2) as s0; ---echo # leading table selection -select * from (select *, vt1.sys_trx_end from t2, vt1) as s0; --echo ### SYSTEM_TIME clash --error ER_VERS_SYSTEM_TIME_CLASH diff --git a/mysql-test/suite/versioning/t/view.test b/mysql-test/suite/versioning/t/view.test index a82949673f63b..e2ad96e70cc5b 100644 --- a/mysql-test/suite/versioning/t/view.test +++ b/mysql-test/suite/versioning/t/view.test @@ -69,11 +69,6 @@ create or replace view vt12 as select * from t1 for system_time as of timestamp select * from vt12; --echo # VIEW improvements [#183] ---error ER_VERS_VIEW_PROHIBITED -create or replace view vt1 as select a, t1.sys_trx_start, t2.sys_trx_end from t1, t2; ---error ER_VERS_VIEW_PROHIBITED -create or replace view vt1 as select a, t1.sys_trx_end, t2.sys_trx_end from t1, t2; - create or replace table t3 (x int); create or replace view vt1 as select * from t1, t2, t3; --replace_result 18446744073709551615 MAX_RESULT "TIMESTAMP'2038-01-19 03:14:07.999999'" MAX_RESULT @@ -89,8 +84,10 @@ show create view vt1; create or replace view vt1 as select * from t1 union select * from t1; select * from vt1; ---error ER_VERS_VIEW_PROHIBITED -create or replace view vvt1 as select * from t1, t2, vt1; +--echo # VIEW over UNION with non-versioned [#393] +create or replace table t2 (a int); +create or replace view vt1 as select * from t1 union select * from t2; +select * from vt1; drop database test; create database test; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index c112af9cd55a2..5646903dfb383 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -841,15 +841,16 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) if (impli_table) { Query_arena_stmt on_stmt_arena(thd); - if (!expli_start && (res= sl->vers_push_field(thd, impli_table, impli_start))) - goto exit; - if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end))) - goto exit; - - if (impli_table->vers_conditions) + SELECT_LEX *outer= sl->outer_select(); + if (outer && outer->table_list.first->vers_conditions) { - sl->vers_export_outer= impli_table->vers_conditions; + if (!expli_start && (res= sl->vers_push_field(thd, impli_table, impli_start))) + goto exit; + if (!expli_end && (res= sl->vers_push_field(thd, impli_table, impli_end))) + goto exit; } + + sl->vers_check_clash= impli_table->vers_conditions; } } // if (sl->table_list.elements > 0) // System Versioning end diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 42e502a5fca08..797c79ccc3dce 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2312,7 +2312,7 @@ void st_select_lex::init_select() curr_tvc_name= 0; in_tvc= false; vers_saved_where= NULL; - vers_export_outer.empty(); + vers_check_clash= false; versioned_tables= 0; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5231dcf173c85..2ac1eb499d2ca 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1048,7 +1048,7 @@ class st_select_lex: public st_select_lex_node private: Item *vers_saved_where; public: - vers_select_conds_t vers_export_outer; + bool vers_check_clash; uint versioned_tables; int vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr); /* push new Item_field into item_list */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bd9068e7ccadd..194bc29a47258 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -676,6 +676,7 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) st_vers_asof_timestamp &in= thd->variables.vers_asof_timestamp; type= (vers_range_type_t) in.type; unit_start= UNIT_TIMESTAMP; + from_query= false; if (type != FOR_SYSTEM_TIME_UNSPECIFIED && type != FOR_SYSTEM_TIME_ALL) { DBUG_ASSERT(type == FOR_SYSTEM_TIME_AS_OF); @@ -738,7 +739,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr { if (table->table && table->table->versioned()) versioned_tables++; - else if (table->vers_conditions) + else if (table->vers_conditions.user_defined()) { my_error(ER_VERSIONING_REQUIRED, MYF(0), table->alias); DBUG_RETURN(-1); @@ -798,22 +799,14 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr SELECT_LEX *outer_slex= next_select_in_list(); // propagate derived conditions to outer SELECT_LEX - if (outer_slex && vers_export_outer) + if (outer_slex && vers_check_clash) { for (table= outer_slex->table_list.first; table; table= table->next_local) { - if (table->vers_conditions) + if (table->vers_conditions && !is_linkage_set()) { - if (!is_linkage_set() && !table->vers_conditions.from_inner) - { - my_error(ER_VERS_SYSTEM_TIME_CLASH, MYF(0), table->alias); - DBUG_RETURN(-1); - } - } - else - { - table->vers_conditions= vers_export_outer; - table->vers_conditions.from_inner= true; + my_error(ER_VERS_SYSTEM_TIME_CLASH, MYF(0), table->alias); + DBUG_RETURN(-1); } } } @@ -832,24 +825,16 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr if (!vers_conditions && outer_slex) { TABLE_LIST* derived= master_unit()->derived; - if (derived == table && vers_export_outer) // recursive CTE + // inner SELECT may not be a derived table (derived == NULL) + while (derived && outer_slex && !derived->vers_conditions) { - vers_conditions= vers_export_outer; + derived= outer_slex->master_unit()->derived; + outer_slex= outer_slex->next_select_in_list(); } - else + if (derived && outer_slex) { - // inner SELECT may not be a derived table (derived == NULL) - while (derived && outer_slex && - (!derived->vers_conditions || derived->vers_conditions.from_inner)) - { - derived= outer_slex->master_unit()->derived; - outer_slex= outer_slex->next_select_in_list(); - } - if (derived && outer_slex && !derived->vers_conditions.from_inner) - { - DBUG_ASSERT(derived->vers_conditions); - vers_conditions= derived->vers_conditions; - } + DBUG_ASSERT(derived->vers_conditions); + vers_conditions= derived->vers_conditions; } } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 6ea4633385b89..21ceb6ce19b5f 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -455,136 +455,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } - for (SELECT_LEX *sl= select_lex; sl; sl= sl->next_select()) - { /* System Versioning: fix system fields of versioned view */ - // Similar logic as in mysql_derived_prepare() - // Leading versioning table detected implicitly (first one selected) - TABLE_LIST *impli_table= NULL; - // Leading versioning table specified explicitly - // (i.e. if at least one system field is selected) - TABLE_LIST *expli_table= NULL; - LEX_CSTRING impli_start, impli_end; - Item_field *expli_start= NULL, *expli_end= NULL; - - for (TABLE_LIST *table= tables; table; table= table->next_local) - { - DBUG_ASSERT(!table->is_view() || table->view); - - // Any versioned table in VIEW will add `FOR SYSTEM_TIME ALL` + WHERE: - // if there are at least one versioned table then VIEW will contain FOR_SYSTEM_TIME_ALL - // (because it is in fact LEX used to parse its SELECT). - if (table->is_view() && table->view->vers_conditions == FOR_SYSTEM_TIME_ALL) - { - my_printf_error( - ER_VERS_VIEW_PROHIBITED, - "Creating VIEW `%s` is prohibited: versioned VIEW `%s` in query!", MYF(0), - view->table_name, - table->table_name); - res= true; - goto err; - } - - if (!table->table || !table->table->versioned()) - continue; - - const LString_i table_start= table->table->vers_start_field()->field_name; - const LString_i table_end= table->table->vers_end_field()->field_name; - - if (!impli_table) - { - impli_table= table; - impli_start= table_start; - impli_end= table_end; - } - - /* Implicitly add versioning fields if needed */ - Item *item; - List_iterator_fast it(sl->item_list); - - DBUG_ASSERT(table->alias); - while ((item= it++)) - { - if (item->real_item()->type() != Item::FIELD_ITEM) - continue; - Item_field *fld= (Item_field*) item->real_item(); - if (fld->table_name && 0 != my_strcasecmp(table_alias_charset, table->alias, fld->table_name)) - continue; - DBUG_ASSERT(fld->field_name.str); - if (table_start == fld->field_name) - { - if (expli_start) - { - my_printf_error( - ER_VERS_VIEW_PROHIBITED, - "Creating VIEW `%s` is prohibited: multiple start system fields `%s.%s`, `%s.%s` in query!", MYF(0), - view->table_name, - expli_table->alias, - expli_start->field_name.str, - table->alias, - fld->field_name.str); - res= true; - goto err; - } - if (expli_table) - { - if (expli_table != table) - { -expli_table_err: - my_printf_error( - ER_VERS_VIEW_PROHIBITED, - "Creating VIEW `%s` is prohibited: system fields from multiple tables `%s`, `%s` in query!", MYF(0), - view->table_name, - expli_table->alias, - table->alias); - res= true; - goto err; - } - } - else - expli_table= table; - expli_start= fld; - impli_end= table_end; - } - else if (table_end == fld->field_name) - { - if (expli_end) - { - my_printf_error( - ER_VERS_VIEW_PROHIBITED, - "Creating VIEW `%s` is prohibited: multiple end system fields `%s.%s`, `%s.%s` in query!", MYF(0), - view->table_name, - expli_table->alias, - expli_end->field_name.str, - table->alias, - fld->field_name.str); - res= true; - goto err; - } - if (expli_table) - { - if (expli_table != table) - goto expli_table_err; - } - else - expli_table= table; - expli_end= fld; - impli_start= table_start; - } - } // while ((item= it++)) - } // for (TABLE_LIST *table) - - if (expli_table) - impli_table= expli_table; - - if (impli_table) - { - if (!expli_start && sl->vers_push_field(thd, impli_table, impli_start)) - goto err; - if (!expli_end && sl->vers_push_field(thd, impli_table, impli_end)) - goto err; - } - } /* System Versioning end */ - view= lex->unlink_first_table(&link_to_local); if (check_db_dir_existence(view->db)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3d637105b3afd..ddad68c349f3b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -752,7 +752,7 @@ inline void vers_select_conds_t::init( unit_end= u_end; start= fix_dec(s); end= fix_dec(e); - import_outer= from_inner= false; + from_query= false; } inline Item *vers_select_conds_t::fix_dec(Item *item) @@ -9206,6 +9206,7 @@ opt_system_time_clause: if (!table->vers_conditions) { table->vers_conditions= Lex->vers_conditions; + table->vers_conditions.from_query= true; used++; } } diff --git a/sql/table.h b/sql/table.h index 1dad990edabf3..a4b7970219386 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1861,21 +1861,20 @@ struct vers_select_conds_t { vers_range_type_t type; vers_range_unit_t unit_start, unit_end; - bool import_outer:1; - bool from_inner:1; + bool from_query:1; Item *start, *end; void empty() { type= FOR_SYSTEM_TIME_UNSPECIFIED; unit_start= unit_end= UNIT_AUTO; - import_outer= from_inner= false; + from_query= false; start= end= NULL; } - inline Item *fix_dec(Item *item); + Item *fix_dec(Item *item); - inline void init( vers_range_type_t t, vers_range_unit_t u_start, + void init( vers_range_type_t t, vers_range_unit_t u_start, Item * s, vers_range_unit_t u_end, Item * e); bool init_from_sysvar(THD *thd); @@ -1893,6 +1892,10 @@ struct vers_select_conds_t return type != FOR_SYSTEM_TIME_UNSPECIFIED; } void resolve_units(bool timestamps_only); + bool user_defined() const + { + return !from_query && type != FOR_SYSTEM_TIME_UNSPECIFIED; + } }; struct LEX;