From 5057d4637525eadad438d25ee6a4870a4e6b384c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 4 Apr 2019 22:41:58 +0200 Subject: [PATCH] bugfix: multi-update checked privileges on views incorrectly it always required UPDATE privilege on views, not being able to detect when a views was not actually updated in multi-update. fix: instead of marking all tables as "updating" by default, only set "updating" on tables that will actually be updated by multi-update. And mark the view "updating" if any of the view's tables is. --- mysql-test/r/view_grant.result | 4 ++++ mysql-test/t/view_grant.test | 5 +++++ sql/sql_lex.h | 4 ++-- sql/sql_parse.cc | 6 +----- sql/sql_update.cc | 4 +++- sql/sql_yacc.yy | 10 +++++----- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index ac09c19a4b4..b2d3a0b8ca4 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -173,11 +173,14 @@ create table mysqltest.t1 (a int, b int, primary key(a)); insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10); create table mysqltest.t2 (x int); insert into mysqltest.t2 values (3), (4), (5), (6); +create table mysqltest.t3 (x int); +insert into mysqltest.t3 values (3), (4), (5), (6); create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1; grant update (a) on mysqltest.v2 to mysqltest_1@localhost; grant update on mysqltest.v1 to mysqltest_1@localhost; +grant update on mysqltest.t3 to mysqltest_1@localhost; grant select on mysqltest.* to mysqltest_1@localhost; use mysqltest; update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c; @@ -212,6 +215,7 @@ a b 48 4 62 5 71 10 +update t3,v3 set t3.x=t3.x+v3.c where t3.x=v3.c; update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c; ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2' update v2 set c=a+c; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index 847153d19f4..ee7374e06f4 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -240,12 +240,15 @@ create table mysqltest.t1 (a int, b int, primary key(a)); insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10); create table mysqltest.t2 (x int); insert into mysqltest.t2 values (3), (4), (5), (6); +create table mysqltest.t3 (x int); +insert into mysqltest.t3 values (3), (4), (5), (6); create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1; grant update (a) on mysqltest.v2 to mysqltest_1@localhost; grant update on mysqltest.v1 to mysqltest_1@localhost; +grant update on mysqltest.t3 to mysqltest_1@localhost; grant select on mysqltest.* to mysqltest_1@localhost; connection user1; @@ -260,6 +263,8 @@ update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c; select * from t1; update v2 set a=a+c; select * from t1; +# update a table, select only on view +update t3,v3 set t3.x=t3.x+v3.c where t3.x=v3.c; # no rights on column --error ER_COLUMNACCESS_DENIED_ERROR update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5b589714e1a..c20994d1ff9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -589,7 +589,7 @@ public: enum_mdl_type mdl_type= MDL_SHARED_READ, List *hints= 0, LEX_STRING *option= 0); - virtual void set_lock_for_tables(thr_lock_type lock_type) {} + virtual void set_lock_for_tables(thr_lock_type lock_type, bool for_update) {} friend class st_select_lex_unit; friend bool mysql_new_select(LEX *lex, bool move_down); @@ -960,7 +960,7 @@ public: TABLE_LIST *convert_right_join(); List* get_item_list(); ulong get_table_join_options(); - void set_lock_for_tables(thr_lock_type lock_type); + void set_lock_for_tables(thr_lock_type lock_type, bool for_update); inline void init_order() { order_list.elements= 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bb53c116b0c..13f5f985d01 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2065,9 +2065,6 @@ mysql_execute_command(THD *thd) reset_one_shot_variables(thd); DBUG_RETURN(0); } - - for (table=all_tables; table; table=table->next_global) - table->updating= TRUE; } /* @@ -6541,9 +6538,8 @@ TABLE_LIST *st_select_lex::convert_right_join() query */ -void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) +void st_select_lex::set_lock_for_tables(thr_lock_type lock_type, bool for_update) { - bool for_update= lock_type >= TL_READ_NO_INSERT; DBUG_ENTER("set_lock_for_tables"); DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type, for_update)); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index fe007d5823d..b23c295a1af 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1305,6 +1305,9 @@ int mysql_multi_update_prepare(THD *thd) If table will be updated we should not downgrade lock for it and leave it as is. */ + tl->updating= 1; + if (tl->belong_to_view) + tl->belong_to_view->updating= 1; } else { @@ -1323,7 +1326,6 @@ int mysql_multi_update_prepare(THD *thd) tl->lock_type= read_lock_type_for_table(thd, lex, tl); else tl->set_lock_type(thd, read_lock_type_for_table(thd, lex, tl)); - tl->updating= 0; } } for (tl= table_list; tl; tl= tl->next_local) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 760aed5c5e3..9fd4cbcc26f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7676,14 +7676,14 @@ select_lock_type: | FOR_SYM UPDATE_SYM { LEX *lex=Lex; - lex->current_select->set_lock_for_tables(TL_WRITE); + lex->current_select->set_lock_for_tables(TL_WRITE, false); lex->safe_to_cache_query=0; } | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM { LEX *lex=Lex; lex->current_select-> - set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); + set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS, false); lex->safe_to_cache_query=0; } ; @@ -10966,7 +10966,7 @@ insert: insert_lock_option opt_ignore insert2 { - Select->set_lock_for_tables($3); + Select->set_lock_for_tables($3, true); Lex->current_select= &Lex->select_lex; } insert_field_spec opt_insert_update @@ -10983,7 +10983,7 @@ replace: } replace_lock_option insert2 { - Select->set_lock_for_tables($3); + Select->set_lock_for_tables($3, true); Lex->current_select= &Lex->select_lex; } insert_field_spec @@ -11174,7 +11174,7 @@ update: be too pessimistic. We will decrease lock level if possible in mysql_multi_update(). */ - slex->set_lock_for_tables($3); + slex->set_lock_for_tables($3, slex->table_list.elements == 1); } where_clause opt_order_clause delete_limit_clause {} ;