diff options
author | Michael Widenius <monty@mariadb.org> | 2014-03-24 08:18:01 +0200 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2014-03-24 08:18:01 +0200 |
commit | 4cc3fd48f6631b8428ea77040829b76f0850ac55 (patch) | |
tree | 484747bddb387be0760dfb845effb675586dac03 /sql/sql_update.cc | |
parent | 7c81a515161cd952c39535546540a1d5b1314b37 (diff) | |
download | mariadb-git-4cc3fd48f6631b8428ea77040829b76f0850ac55.tar.gz |
MDEV-5876: MySQL bug #11766767 - "59957: VIEW USING MERGE PERMISSIONS IN MULTI-TABLE UPDATE"
Backported multi_update_check_table_access() from 5.6
The code is slightly different in MariaDB, becasue we instansiate fields in merged tables earlier.
mysql-test/mysql-test-run.pl:
Fixed comment
mysql-test/r/view_grant.result:
Merged test case from 5.6
mysql-test/t/view_grant.test:
Merged test case from 5.6
sql/sql_parse.cc:
Reset orig_want_privilege as this will be rechecked later.
If not, we will have a problem in mysql_multi_update_prepare() for the call to mysql_handle_derived()
sql/sql_update.cc:
Backport multi_update_check_table_access() from 5.6
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r-- | sql/sql_update.cc | 101 |
1 files changed, 90 insertions, 11 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b9655984264..01fe0336814 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1217,6 +1217,87 @@ bool unsafe_key_update(List<TABLE_LIST> leaves, table_map tables_for_update) return false; } +/** + Check if there is enough privilege on specific table used by the + main select list of multi-update directly or indirectly (through + a view). + + @param[in] thd Thread context. + @param[in] table Table list element for the table. + @param[in] tables_for_update Bitmap with tables being updated. + @param[in/out] updated_arg Set to true if table in question is + updated, also set to true if it is + a view and one of its underlying + tables is updated. Should be + initialized to false by the caller + before a sequence of calls to this + function. + + @note To determine which tables/views are updated we have to go from + leaves to root since tables_for_update contains map of leaf + tables being updated and doesn't include non-leaf tables + (fields are already resolved to leaf tables). + + @retval false - Success, all necessary privileges on all tables are + present or might be present on column-level. + @retval true - Failure, some necessary privilege on some table is + missing. +*/ + +static bool multi_update_check_table_access(THD *thd, TABLE_LIST *table, + table_map tables_for_update, + bool *updated_arg) +{ + if (table->view) + { + bool updated= false; + /* + If it is a mergeable view then we need to check privileges on its + underlying tables being merged (including views). We also need to + check if any of them is updated in order to find if this view is + updated. + If it is a non-mergeable view then it can't be updated. + */ + DBUG_ASSERT(table->merge_underlying_list || + (!table->updatable && + !(table->table->map & tables_for_update))); + + for (TABLE_LIST *tbl= table->merge_underlying_list; tbl; + tbl= tbl->next_local) + { + if (multi_update_check_table_access(thd, tbl, tables_for_update, + &updated)) + { + tbl->hide_view_error(thd); + return true; + } + } + if (check_table_access(thd, updated ? UPDATE_ACL: SELECT_ACL, table, + FALSE, 1, FALSE)) + return true; + *updated_arg|= updated; + /* We only need SELECT privilege for columns in the values list. */ + table->grant.want_privilege= SELECT_ACL & ~table->grant.privilege; + } + else + { + /* Must be a base or derived table. */ + const bool updated= table->table->map & tables_for_update; + if (check_table_access(thd, updated ? UPDATE_ACL : SELECT_ACL, table, + FALSE, 1, FALSE)) + return true; + *updated_arg|= updated; + /* We only need SELECT privilege for columns in the values list. */ + if (!table->derived) + { + table->grant.want_privilege= SELECT_ACL & ~table->grant.privilege; + table->table->grant.want_privilege= (SELECT_ACL & + ~table->table->grant.privilege); + } + } + return false; +} + /* make update specific preparation and checks after opening tables @@ -1351,19 +1432,17 @@ int mysql_multi_update_prepare(THD *thd) tl->table->reginfo.lock_type= tl->lock_type; } } + + /* + Check access privileges for tables being updated or read. + Note that unlike in the above loop we need to iterate here not only + through all leaf tables but also through all view hierarchy. + */ for (tl= table_list; tl; tl= tl->next_local) { - /* Check access privileges for table */ - if (!tl->is_derived()) - { - uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL; - if (check_access(thd, want_privilege, tl->db, - &tl->grant.privilege, - &tl->grant.m_internal, - 0, 0) || - check_grant(thd, want_privilege, tl, FALSE, 1, FALSE)) - DBUG_RETURN(TRUE); - } + bool not_used= false; + if (multi_update_check_table_access(thd, tl, tables_for_update, ¬_used)) + DBUG_RETURN(TRUE); } /* check single table update for view compound from several tables */ |