-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MDEV-12666: CURRENT_ROLE() and DATABASE() does not work in a view
The problem lies in how CURRENT_ROLE is defined. The Item_func_current_role inherits from Item_func_sysconst, which defines a safe_charset_converter to be a const_charset_converter. During view creation, if there is no role previously set, the current_role() function returns NULL. This is captured on item instantiation and the const_charset_converter call subsequently returns an Item_null. In turn, the function is replaced with Item_null and the view is then created with an Item_null instead of Item_func_current_role. Without this patch, the first SHOW CREATE VIEW from the testcase would have a where clause of WHERE role_name = NULL, while the second SHOW CREATE VIEW would show a correctly created view. The same applies for the DATABASE function, as it can change as well. There is an additional problem with CURRENT_ROLE() when used in a prepared statement. During prepared statement creation we used to set the string_value of the function to the current role as well as the null_value flag. During execution, if CURRENT_ROLE was not null, the null_value flag was never set to not-null during fix_fields. Item_func_current_user however can never be NULL so it did not show this problem in a view before. At the same time, the CURRENT_USER() can not be changed between prepared statement execution and creation so the implementation where the value is stored during fix_fields is sufficient. Note also that DATABASE() function behaves differently during prepared statements. See bug 25843 for details or commit 7e0ad09
- Loading branch information
Showing
8 changed files
with
345 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
CREATE USER has_role@'localhost'; | ||
GRANT ALL PRIVILEGES ON *.* TO has_role@'localhost'; | ||
CREATE ROLE test_role; | ||
GRANT test_role TO has_role@'localhost'; | ||
CREATE USER no_role@'localhost'; | ||
GRANT ALL PRIVILEGES ON *.* TO no_role@'localhost'; | ||
CREATE TABLE view_role_test ( | ||
id int primary key, | ||
role_name varchar(50) | ||
); | ||
INSERT INTO view_role_test VALUES (1, 'test_role'); | ||
# | ||
# Use the same logic for stored procedures. | ||
# | ||
PREPARE prepared_no_current_role FROM "SELECT * from view_role_test WHERE role_name = CURRENT_ROLE()"; | ||
# | ||
# Creating a view with no CURRENT_ROLE() set and one with CURRENT_ROLE() | ||
# set. Both should produce the same SHOW CREATE VIEW output. | ||
# | ||
CREATE | ||
DEFINER = no_role@localhost | ||
SQL SECURITY INVOKER | ||
VIEW v_view_role_test_no_current_role | ||
AS | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
SHOW CREATE VIEW v_view_role_test_no_current_role; | ||
View Create View character_set_client collation_connection | ||
v_view_role_test_no_current_role CREATE ALGORITHM=UNDEFINED DEFINER=`no_role`@`localhost` SQL SECURITY INVOKER VIEW `v_view_role_test_no_current_role` AS select `view_role_test`.`id` AS `id`,`view_role_test`.`role_name` AS `role_name` from `view_role_test` where (`view_role_test`.`role_name` = current_role()) latin1 latin1_swedish_ci | ||
# | ||
# No values should be returned | ||
# | ||
EXECUTE prepared_no_current_role; | ||
id role_name | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
id role_name | ||
SELECT * FROM v_view_role_test_no_current_role; | ||
id role_name | ||
# | ||
# Now let's set the role. Create identical views as before. See if | ||
# their behaviour is different. It should not be. | ||
# | ||
SET ROLE test_role; | ||
SELECT CURRENT_USER(); | ||
CURRENT_USER() | ||
root@localhost | ||
SELECT CURRENT_ROLE(); | ||
CURRENT_ROLE() | ||
test_role | ||
# | ||
# Create the VIEW and prepared Statement with a CURRENT_ROLE() set. | ||
# | ||
CREATE | ||
DEFINER = no_role@localhost | ||
SQL SECURITY INVOKER | ||
VIEW v_view_role_test_with_current_role | ||
AS | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
PREPARE prepared_with_current_role FROM "SELECT * from view_role_test WHERE role_name = CURRENT_ROLE()"; | ||
SHOW CREATE VIEW v_view_role_test_with_current_role; | ||
View Create View character_set_client collation_connection | ||
v_view_role_test_with_current_role CREATE ALGORITHM=UNDEFINED DEFINER=`no_role`@`localhost` SQL SECURITY INVOKER VIEW `v_view_role_test_with_current_role` AS select `view_role_test`.`id` AS `id`,`view_role_test`.`role_name` AS `role_name` from `view_role_test` where (`view_role_test`.`role_name` = current_role()) latin1 latin1_swedish_ci | ||
# | ||
# Values should be returned for all select statements as we do have | ||
# a CURRENT_ROLE() active; | ||
# | ||
EXECUTE prepared_no_current_role; | ||
id role_name | ||
1 test_role | ||
EXECUTE prepared_with_current_role; | ||
id role_name | ||
1 test_role | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
id role_name | ||
1 test_role | ||
SELECT * FROM v_view_role_test_no_current_role; | ||
id role_name | ||
1 test_role | ||
SELECT * FROM v_view_role_test_with_current_role; | ||
id role_name | ||
1 test_role | ||
SET ROLE NONE; | ||
# | ||
# No values should be returned for all select statements as we do not have | ||
# a CURRENT_ROLE() active; | ||
# | ||
EXECUTE prepared_no_current_role; | ||
id role_name | ||
EXECUTE prepared_with_current_role; | ||
id role_name | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
id role_name | ||
SELECT * FROM v_view_role_test_no_current_role; | ||
id role_name | ||
SELECT * FROM v_view_role_test_with_current_role; | ||
id role_name | ||
DROP USER has_role@'localhost'; | ||
DROP USER no_role@'localhost'; | ||
DROP ROLE test_role; | ||
DROP table view_role_test; | ||
DROP VIEW v_view_role_test_no_current_role; | ||
DROP VIEW v_view_role_test_with_current_role; | ||
DROP PREPARE prepared_no_current_role; | ||
DROP PREPARE prepared_with_current_role; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# | ||
# MDEV-12666 CURRENT_ROLE() does not work in a view | ||
# | ||
--source include/not_embedded.inc | ||
|
||
CREATE USER has_role@'localhost'; | ||
GRANT ALL PRIVILEGES ON *.* TO has_role@'localhost'; | ||
|
||
CREATE ROLE test_role; | ||
GRANT test_role TO has_role@'localhost'; | ||
|
||
CREATE USER no_role@'localhost'; | ||
GRANT ALL PRIVILEGES ON *.* TO no_role@'localhost'; | ||
|
||
CREATE TABLE view_role_test ( | ||
id int primary key, | ||
role_name varchar(50) | ||
); | ||
|
||
INSERT INTO view_role_test VALUES (1, 'test_role'); | ||
|
||
--echo # | ||
--echo # Use the same logic for stored procedures. | ||
--echo # | ||
PREPARE prepared_no_current_role FROM "SELECT * from view_role_test WHERE role_name = CURRENT_ROLE()"; | ||
|
||
--echo # | ||
--echo # Creating a view with no CURRENT_ROLE() set and one with CURRENT_ROLE() | ||
--echo # set. Both should produce the same SHOW CREATE VIEW output. | ||
--echo # | ||
CREATE | ||
DEFINER = no_role@localhost | ||
SQL SECURITY INVOKER | ||
VIEW v_view_role_test_no_current_role | ||
AS | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
|
||
SHOW CREATE VIEW v_view_role_test_no_current_role; | ||
|
||
|
||
--echo # | ||
--echo # No values should be returned | ||
--echo # | ||
EXECUTE prepared_no_current_role; | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
SELECT * FROM v_view_role_test_no_current_role; | ||
|
||
--echo # | ||
--echo # Now let's set the role. Create identical views as before. See if | ||
--echo # their behaviour is different. It should not be. | ||
--echo # | ||
SET ROLE test_role; | ||
|
||
SELECT CURRENT_USER(); | ||
SELECT CURRENT_ROLE(); | ||
|
||
--echo # | ||
--echo # Create the VIEW and prepared Statement with a CURRENT_ROLE() set. | ||
--echo # | ||
CREATE | ||
DEFINER = no_role@localhost | ||
SQL SECURITY INVOKER | ||
VIEW v_view_role_test_with_current_role | ||
AS | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
|
||
PREPARE prepared_with_current_role FROM "SELECT * from view_role_test WHERE role_name = CURRENT_ROLE()"; | ||
|
||
SHOW CREATE VIEW v_view_role_test_with_current_role; | ||
|
||
|
||
--echo # | ||
--echo # Values should be returned for all select statements as we do have | ||
--echo # a CURRENT_ROLE() active; | ||
--echo # | ||
EXECUTE prepared_no_current_role; | ||
EXECUTE prepared_with_current_role; | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
SELECT * FROM v_view_role_test_no_current_role; | ||
SELECT * FROM v_view_role_test_with_current_role; | ||
|
||
SET ROLE NONE; | ||
--echo # | ||
--echo # No values should be returned for all select statements as we do not have | ||
--echo # a CURRENT_ROLE() active; | ||
--echo # | ||
EXECUTE prepared_no_current_role; | ||
EXECUTE prepared_with_current_role; | ||
SELECT * FROM view_role_test WHERE role_name = CURRENT_ROLE(); | ||
SELECT * FROM v_view_role_test_no_current_role; | ||
SELECT * FROM v_view_role_test_with_current_role; | ||
|
||
|
||
DROP USER has_role@'localhost'; | ||
DROP USER no_role@'localhost'; | ||
DROP ROLE test_role; | ||
|
||
DROP table view_role_test; | ||
DROP VIEW v_view_role_test_no_current_role; | ||
DROP VIEW v_view_role_test_with_current_role; | ||
DROP PREPARE prepared_no_current_role; | ||
DROP PREPARE prepared_with_current_role; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.