mariadb/mysql-test/suite/roles/current_role_view-12666.result

104 lines
3.6 KiB
Text
Raw Normal View History

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 7e0ad09edff587dadc3e9855fc81e1b7de8f2199
2017-05-22 17:06:01 +03:00
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
2017-07-05 19:08:55 +02:00
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
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 7e0ad09edff587dadc3e9855fc81e1b7de8f2199
2017-05-22 17:06:01 +03:00
#
# 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
2017-07-05 19:08:55 +02:00
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
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 7e0ad09edff587dadc3e9855fc81e1b7de8f2199
2017-05-22 17:06:01 +03:00
#
# 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;