diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 64aee1fd078..5656f66a935 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -5036,6 +5036,24 @@ id test 1 0 drop view v1; drop table t1; +# +# MDEV-5981: name resolution issues with views and multi-update +# in ps-protocol +# +create table t1 (id1 int primary key, val1 varchar(20)); +insert into t1 values (1, 'test1'); +create table t2 (id2 int primary key, val2 varchar(20)); +insert into t2 values (1, 'test2'); +create algorithm=merge view v1 as select id1 as id1v1, val1 as val1v1 from t1; +create algorithm=merge view v2 as +select t2.id2 as id2v2, t2.val2 as val2v2 +from t2, v1 +where t2.id2 = v1.id1v1; +prepare stmt1 from "update v2 set val2v2 = 'test19' where 1 = id2v2"; +execute stmt1; +deallocate prepare stmt1; +drop view v1,v2; +drop table t1,t2; # ----------------------------------------------------------------- # -- End of 5.3 tests. # ----------------------------------------------------------------- diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index a814132e165..13fdb8283fa 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -4952,6 +4952,25 @@ select * from v1; drop view v1; drop table t1; +--echo # +--echo # MDEV-5981: name resolution issues with views and multi-update +--echo # in ps-protocol +--echo # + +create table t1 (id1 int primary key, val1 varchar(20)); +insert into t1 values (1, 'test1'); +create table t2 (id2 int primary key, val2 varchar(20)); +insert into t2 values (1, 'test2'); +create algorithm=merge view v1 as select id1 as id1v1, val1 as val1v1 from t1; +create algorithm=merge view v2 as +select t2.id2 as id2v2, t2.val2 as val2v2 +from t2, v1 +where t2.id2 = v1.id1v1; +prepare stmt1 from "update v2 set val2v2 = 'test19' where 1 = id2v2"; +execute stmt1; +deallocate prepare stmt1; +drop view v1,v2; +drop table t1,t2; --echo # ----------------------------------------------------------------- --echo # -- End of 5.3 tests. --echo # ----------------------------------------------------------------- diff --git a/sql/item.cc b/sql/item.cc index b3d4b4a7616..7a650ca75c7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4697,6 +4697,10 @@ bool is_outer_table(TABLE_LIST *table, SELECT_LEX *select) DBUG_ASSERT(table->select_lex != select); TABLE_LIST *tl; + if (table->belong_to_view && + table->belong_to_view->select_lex == select) + return FALSE; + for (tl= select->master_unit()->derived; tl && tl->is_merged_derived(); select= tl->select_lex, tl= select->master_unit()->derived) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3eefd8e8835..577d667b450 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8747,6 +8747,75 @@ void wrap_ident(THD *thd, Item **conds) thd->restore_active_arena(arena, &backup); } +/** + Prepare ON expression + + @param thd Thread handle + @param table Pointer to table list + @param is_update Update flag + + @retval TRUE error. + @retval FALSE OK. +*/ + +bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) +{ + uchar buff[STACK_BUFF_ALLOC]; // Max argument in function + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) + return TRUE; // Fatal error flag is set! + for(; table; table= table->next_local) + { + TABLE_LIST *embedded; /* The table at the current level of nesting. */ + TABLE_LIST *embedding= table; /* The parent nested table reference. */ + do + { + embedded= embedding; + DBUG_PRINT("XXX", ("check: %s", table->alias)); + if (embedded->on_expr) + { + thd->where="on clause"; + embedded->on_expr->mark_as_condition_AND_part(embedded); + if ((!embedded->on_expr->fixed && + embedded->on_expr->fix_fields(thd, &embedded->on_expr)) || + embedded->on_expr->check_cols(1)) + return TRUE; + } + /* + If it's a semi-join nest, fix its "left expression", as it is used by + the SJ-Materialization + */ + if (embedded->sj_subq_pred) + { + Item **left_expr= &embedded->sj_subq_pred->left_expr; + if (!(*left_expr)->fixed && (*left_expr)->fix_fields(thd, left_expr)) + return TRUE; + } + + embedding= embedded->embedding; + } + while (embedding && + embedding->nested_join->join_list.head() == embedded); + + if (table->is_merged_derived()) + { + SELECT_LEX *select_lex= table->get_single_select(); + setup_on_expr(thd, select_lex->get_table_list(), is_update); + } + + /* process CHECK OPTION */ + if (is_update) + { + TABLE_LIST *view= table->top_table(); + if (view->effective_with_check) + { + if (view->prepare_check_option(thd)) + return TRUE; + thd->change_item_tree(&table->check_option, view->check_option); + } + } + } + return FALSE; +} /* Fix all conditions and outer join expressions. @@ -8771,7 +8840,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List &leaves, { SELECT_LEX *select_lex= thd->lex->current_select; TABLE_LIST *table= NULL; // For HP compilers - List_iterator ti(leaves); /* it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX which belong to LEX, i.e. most up SELECT) will be updated by @@ -8830,51 +8898,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List &leaves, Apply fix_fields() to all ON clauses at all levels of nesting, including the ones inside view definitions. */ - while ((table= ti++)) - { - TABLE_LIST *embedded; /* The table at the current level of nesting. */ - TABLE_LIST *embedding= table; /* The parent nested table reference. */ - do - { - embedded= embedding; - if (embedded->on_expr) - { - /* Make a join an a expression */ - thd->where="on clause"; - embedded->on_expr->mark_as_condition_AND_part(embedded); - if ((!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, &embedded->on_expr)) || - embedded->on_expr->check_cols(1)) - goto err_no_arena; - } - /* - If it's a semi-join nest, fix its "left expression", as it is used by - the SJ-Materialization - */ - if (embedded->sj_subq_pred) - { - Item **left_expr= &embedded->sj_subq_pred->left_expr; - if (!(*left_expr)->fixed && (*left_expr)->fix_fields(thd, left_expr)) - goto err_no_arena; - } - - embedding= embedded->embedding; - } - while (embedding && - embedding->nested_join->join_list.head() == embedded); - - /* process CHECK OPTION */ - if (it_is_update) - { - TABLE_LIST *view= table->top_table(); - if (view->effective_with_check) - { - if (view->prepare_check_option(thd)) - goto err_no_arena; - thd->change_item_tree(&table->check_option, view->check_option); - } - } - } + if (setup_on_expr(thd, tables, it_is_update)) + goto err_no_arena; if (!thd->stmt_arena->is_conventional()) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e275a7ffee7..1f591624457 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -646,7 +646,9 @@ JOIN::prepare(Item ***rref_pointer_array, if (!(select_options & OPTION_SETUP_TABLES_DONE) && setup_tables_and_check_access(thd, &select_lex->context, join_list, tables_list, select_lex->leaf_tables, - FALSE, SELECT_ACL, SELECT_ACL, FALSE)) + FALSE, SELECT_ACL, SELECT_ACL, + (thd->lex->sql_command == + SQLCOM_UPDATE_MULTI))) DBUG_RETURN(-1); /*