mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 18:20:07 +01:00
support of view underlying tables and SP functions security check added (BUG#9505) (WL#2787)
This commit is contained in:
parent
bee76b78a2
commit
1b164c7b83
24 changed files with 957 additions and 176 deletions
mysql-test
r
t
sql
|
@ -648,21 +648,21 @@ select table_name from information_schema.views
|
|||
where table_schema='test';
|
||||
table_name
|
||||
Warnings:
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select table_name from information_schema.views
|
||||
where table_schema='test';
|
||||
table_name
|
||||
Warnings:
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select column_name from information_schema.columns
|
||||
where table_schema='test';
|
||||
column_name
|
||||
f1
|
||||
Warnings:
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select index_name from information_schema.statistics where table_schema='test';
|
||||
index_name
|
||||
f1_key
|
||||
|
|
|
@ -1032,7 +1032,7 @@ a f8()
|
|||
3 1
|
||||
drop function f1|
|
||||
select * from v1|
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
create function f1() returns int
|
||||
return (select sum(data) from t1) + (select sum(data) from v1)|
|
||||
drop function f1|
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
drop table if exists t1;
|
||||
drop table if exists t1,t2,v1,v2;
|
||||
drop view if exists t1,t2,v1,v2;
|
||||
CREATE TABLE `t1` (
|
||||
a int not null auto_increment,
|
||||
`pseudo` varchar(35) character set latin2 NOT NULL default '',
|
||||
|
|
|
@ -574,10 +574,10 @@ create view v1 as select * from t1;
|
|||
drop table t1;
|
||||
create table t1 (col1 char(5),newcol2 char(5));
|
||||
insert into v1 values('a','aa');
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
drop table t1;
|
||||
select * from v1;
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
drop view v1;
|
||||
create view v1 (a,a) as select 'a','a';
|
||||
ERROR 42S21: Duplicate column name 'a'
|
||||
|
@ -809,11 +809,11 @@ create table t1 (s1 int);
|
|||
create view v1 as select x1() from t1;
|
||||
drop function x1;
|
||||
select * from v1;
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
show table status;
|
||||
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
|
||||
t1 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
|
||||
v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL View 'test.v1' references invalid table(s) or column(s) or function(s) or define
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1;
|
||||
|
@ -1360,7 +1360,7 @@ test.t1 check status OK
|
|||
drop table t1;
|
||||
check table v1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
drop view v1;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
|
@ -1884,11 +1884,11 @@ CREATE VIEW v6 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2;
|
|||
DROP TABLE t1;
|
||||
CHECK TABLE v1, v2, v3, v4, v5, v6;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v2 check status OK
|
||||
test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v4 check status OK
|
||||
test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s)
|
||||
test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v6 check status OK
|
||||
drop view v1, v2, v3, v4, v5, v6;
|
||||
drop table t2;
|
||||
|
@ -1908,11 +1908,11 @@ CREATE VIEW v6 AS SELECT f2() FROM t3;
|
|||
drop function f1;
|
||||
CHECK TABLE v1, v2, v3, v4, v5, v6;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v2 check status OK
|
||||
test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v4 check status OK
|
||||
test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s)
|
||||
test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v6 check status OK
|
||||
create function f1 () returns int return (select max(col1) from t1);
|
||||
DROP TABLE t1;
|
||||
|
@ -2154,7 +2154,7 @@ Field Type Null Key Default Extra
|
|||
f4 char(5) YES NULL
|
||||
ALTER TABLE t1 CHANGE COLUMN f4 f4x CHAR(5);
|
||||
DESCRIBE v1;
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
DROP TABLE t1;
|
||||
DROP VIEW v1;
|
||||
create table t1 (f1 char);
|
||||
|
|
|
@ -305,5 +305,172 @@ create table mysqltest.t1 (a int);
|
|||
grant all privileges on mysqltest.* to mysqltest_1@localhost;
|
||||
use mysqltest;
|
||||
create view v1 as select * from t1;
|
||||
use test;
|
||||
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
create database mysqltest;
|
||||
create table mysqltest.t1 (a int, b int);
|
||||
grant select on mysqltest.t1 to mysqltest_1@localhost;
|
||||
grant create view,select on test.* to mysqltest_1@localhost;
|
||||
create view v1 as select * from mysqltest.t1;
|
||||
show create view v1;
|
||||
View Create View
|
||||
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_1`@`localhost` SQL SECURITY DEFINER VIEW `test`.`v1` AS select `mysqltest`.`t1`.`a` AS `a`,`mysqltest`.`t1`.`b` AS `b` from `mysqltest`.`t1`
|
||||
revoke select on mysqltest.t1 from mysqltest_1@localhost;
|
||||
select * from v1;
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
grant select on mysqltest.t1 to mysqltest_1@localhost;
|
||||
select * from v1;
|
||||
a b
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop view v1;
|
||||
drop database mysqltest;
|
||||
create database mysqltest;
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
insert into t1 values (1);
|
||||
create table t2 (s1 int);
|
||||
drop function if exists f2;
|
||||
create function f2 () returns int begin declare v int; select s1 from t2
|
||||
into v; return v; end//
|
||||
create algorithm=TEMPTABLE view v1 as select f2() from t1;
|
||||
create algorithm=MERGE view v2 as select f2() from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1;
|
||||
create SQL SECURITY INVOKER view v5 as select * from v4;
|
||||
grant select on v1 to mysqltest_1@localhost;
|
||||
grant select on v2 to mysqltest_1@localhost;
|
||||
grant select on v3 to mysqltest_1@localhost;
|
||||
grant select on v4 to mysqltest_1@localhost;
|
||||
grant select on v5 to mysqltest_1@localhost;
|
||||
use mysqltest;
|
||||
select * from v1;
|
||||
f2()
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1329 No data to FETCH
|
||||
select * from v2;
|
||||
f2()
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1329 No data to FETCH
|
||||
select * from v3;
|
||||
ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v4;
|
||||
ERROR HY000: View 'mysqltest.v4' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v5;
|
||||
ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
use test;
|
||||
drop view v1, v2, v3, v4, v5;
|
||||
drop function f2;
|
||||
drop table t1, t2;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
create database mysqltest;
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
insert into t1 values (1);
|
||||
create table t2 (s1 int);
|
||||
drop function if exists f2;
|
||||
create function f2 () returns int begin declare v int; select s1 from t2
|
||||
into v; return v; end//
|
||||
grant select on t1 to mysqltest_1@localhost;
|
||||
grant execute on function f2 to mysqltest_1@localhost;
|
||||
grant create view on mysqltest.* to mysqltest_1@localhost;
|
||||
use mysqltest;
|
||||
create algorithm=TEMPTABLE view v1 as select f2() from t1;
|
||||
create algorithm=MERGE view v2 as select f2() from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1;
|
||||
use test;
|
||||
create view v5 as select * from v1;
|
||||
revoke execute on function f2 from mysqltest_1@localhost;
|
||||
select * from v1;
|
||||
ERROR HY000: View 'mysqltest.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v2;
|
||||
ERROR HY000: View 'mysqltest.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v3;
|
||||
f2()
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1329 No data to FETCH
|
||||
select * from v4;
|
||||
f2()
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 1329 No data to FETCH
|
||||
select * from v5;
|
||||
ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
drop view v1, v2, v3, v4, v5;
|
||||
drop function f2;
|
||||
drop table t1, t2;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
create database mysqltest;
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
create table v1 (a int);
|
||||
insert into t1 values (1);
|
||||
grant select on t1 to mysqltest_1@localhost;
|
||||
grant select on v1 to mysqltest_1@localhost;
|
||||
grant create view on mysqltest.* to mysqltest_1@localhost;
|
||||
drop table v1;
|
||||
use mysqltest;
|
||||
create algorithm=TEMPTABLE view v1 as select *, a as b from t1;
|
||||
create algorithm=MERGE view v2 as select *, a as b from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1;
|
||||
create view v5 as select * from v1;
|
||||
use test;
|
||||
revoke select on t1 from mysqltest_1@localhost;
|
||||
select * from v1;
|
||||
ERROR HY000: View 'mysqltest.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v2;
|
||||
ERROR HY000: View 'mysqltest.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v3;
|
||||
a b
|
||||
1 1
|
||||
select * from v4;
|
||||
a b
|
||||
1 1
|
||||
select * from v5;
|
||||
ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
drop table t1;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
create database mysqltest;
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
insert into t1 values (1);
|
||||
create algorithm=TEMPTABLE view v1 as select *, a as b from t1;
|
||||
create algorithm=MERGE view v2 as select *, a as b from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1;
|
||||
create SQL SECURITY INVOKER view v5 as select * from v4;
|
||||
grant select on v1 to mysqltest_1@localhost;
|
||||
grant select on v2 to mysqltest_1@localhost;
|
||||
grant select on v3 to mysqltest_1@localhost;
|
||||
grant select on v4 to mysqltest_1@localhost;
|
||||
grant select on v5 to mysqltest_1@localhost;
|
||||
use mysqltest;
|
||||
select * from v1;
|
||||
a b
|
||||
1 1
|
||||
select * from v2;
|
||||
a b
|
||||
1 1
|
||||
select * from v3;
|
||||
ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v4;
|
||||
ERROR HY000: View 'mysqltest.v4' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from v5;
|
||||
ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
use test;
|
||||
drop view v1, v2, v3, v4, v5;
|
||||
drop table t1;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
drop table if exists t1,t2,v1,v2;
|
||||
drop view if exists t1,t2,v1,v2;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE `t1` (
|
||||
|
|
|
@ -401,8 +401,221 @@ grant all privileges on mysqltest.* to mysqltest_1@localhost;
|
|||
connection user1;
|
||||
use mysqltest;
|
||||
create view v1 as select * from t1;
|
||||
use test;
|
||||
|
||||
connection root;
|
||||
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
|
||||
#
|
||||
# view definer grants revoking
|
||||
#
|
||||
connection root;
|
||||
--disable_warnings
|
||||
create database mysqltest;
|
||||
--enable_warnings
|
||||
|
||||
create table mysqltest.t1 (a int, b int);
|
||||
|
||||
grant select on mysqltest.t1 to mysqltest_1@localhost;
|
||||
grant create view,select on test.* to mysqltest_1@localhost;
|
||||
|
||||
connection user1;
|
||||
|
||||
create view v1 as select * from mysqltest.t1;
|
||||
|
||||
connection root;
|
||||
# check view definer information
|
||||
show create view v1;
|
||||
revoke select on mysqltest.t1 from mysqltest_1@localhost;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v1;
|
||||
grant select on mysqltest.t1 to mysqltest_1@localhost;
|
||||
select * from v1;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop view v1;
|
||||
drop database mysqltest;
|
||||
|
||||
#
|
||||
# rights on execution of view underlying functiond (BUG#9505)
|
||||
#
|
||||
connection root;
|
||||
--disable_warnings
|
||||
create database mysqltest;
|
||||
--enable_warnings
|
||||
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
insert into t1 values (1);
|
||||
create table t2 (s1 int);
|
||||
--disable_warnings
|
||||
drop function if exists f2;
|
||||
--enable_warnings
|
||||
delimiter //;
|
||||
create function f2 () returns int begin declare v int; select s1 from t2
|
||||
into v; return v; end//
|
||||
delimiter ;//
|
||||
create algorithm=TEMPTABLE view v1 as select f2() from t1;
|
||||
create algorithm=MERGE view v2 as select f2() from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1;
|
||||
create SQL SECURITY INVOKER view v5 as select * from v4;
|
||||
grant select on v1 to mysqltest_1@localhost;
|
||||
grant select on v2 to mysqltest_1@localhost;
|
||||
grant select on v3 to mysqltest_1@localhost;
|
||||
grant select on v4 to mysqltest_1@localhost;
|
||||
grant select on v5 to mysqltest_1@localhost;
|
||||
|
||||
connection user1;
|
||||
use mysqltest;
|
||||
select * from v1;
|
||||
select * from v2;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v3;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v4;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v5;
|
||||
use test;
|
||||
|
||||
connection root;
|
||||
drop view v1, v2, v3, v4, v5;
|
||||
drop function f2;
|
||||
drop table t1, t2;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
|
||||
#
|
||||
# revertion of previous test, definer of view lost his/her rights to execute
|
||||
# function
|
||||
#
|
||||
|
||||
connection root;
|
||||
--disable_warnings
|
||||
create database mysqltest;
|
||||
--enable_warnings
|
||||
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
insert into t1 values (1);
|
||||
create table t2 (s1 int);
|
||||
--disable_warnings
|
||||
drop function if exists f2;
|
||||
--enable_warnings
|
||||
delimiter //;
|
||||
create function f2 () returns int begin declare v int; select s1 from t2
|
||||
into v; return v; end//
|
||||
delimiter ;//
|
||||
grant select on t1 to mysqltest_1@localhost;
|
||||
grant execute on function f2 to mysqltest_1@localhost;
|
||||
grant create view on mysqltest.* to mysqltest_1@localhost;
|
||||
|
||||
connection user1;
|
||||
use mysqltest;
|
||||
create algorithm=TEMPTABLE view v1 as select f2() from t1;
|
||||
create algorithm=MERGE view v2 as select f2() from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1;
|
||||
use test;
|
||||
|
||||
connection root;
|
||||
create view v5 as select * from v1;
|
||||
revoke execute on function f2 from mysqltest_1@localhost;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v1;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v2;
|
||||
select * from v3;
|
||||
select * from v4;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v5;
|
||||
|
||||
drop view v1, v2, v3, v4, v5;
|
||||
drop function f2;
|
||||
drop table t1, t2;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
|
||||
#
|
||||
# definer/invoker rights for columns
|
||||
#
|
||||
connection root;
|
||||
--disable_warnings
|
||||
create database mysqltest;
|
||||
--enable_warnings
|
||||
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
create table v1 (a int);
|
||||
insert into t1 values (1);
|
||||
grant select on t1 to mysqltest_1@localhost;
|
||||
grant select on v1 to mysqltest_1@localhost;
|
||||
grant create view on mysqltest.* to mysqltest_1@localhost;
|
||||
drop table v1;
|
||||
|
||||
connection user1;
|
||||
use mysqltest;
|
||||
create algorithm=TEMPTABLE view v1 as select *, a as b from t1;
|
||||
create algorithm=MERGE view v2 as select *, a as b from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1;
|
||||
create view v5 as select * from v1;
|
||||
use test;
|
||||
|
||||
connection root;
|
||||
revoke select on t1 from mysqltest_1@localhost;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v1;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v2;
|
||||
select * from v3;
|
||||
select * from v4;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v5;
|
||||
|
||||
#drop view v1, v2, v3, v4, v5;
|
||||
drop table t1;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
|
||||
|
||||
connection root;
|
||||
--disable_warnings
|
||||
create database mysqltest;
|
||||
--enable_warnings
|
||||
|
||||
use mysqltest;
|
||||
create table t1 (a int);
|
||||
insert into t1 values (1);
|
||||
create algorithm=TEMPTABLE view v1 as select *, a as b from t1;
|
||||
create algorithm=MERGE view v2 as select *, a as b from t1;
|
||||
create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1;
|
||||
create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1;
|
||||
create SQL SECURITY INVOKER view v5 as select * from v4;
|
||||
grant select on v1 to mysqltest_1@localhost;
|
||||
grant select on v2 to mysqltest_1@localhost;
|
||||
grant select on v3 to mysqltest_1@localhost;
|
||||
grant select on v4 to mysqltest_1@localhost;
|
||||
grant select on v5 to mysqltest_1@localhost;
|
||||
|
||||
connection user1;
|
||||
use mysqltest;
|
||||
select * from v1;
|
||||
select * from v2;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v3;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v4;
|
||||
-- error ER_VIEW_INVALID
|
||||
select * from v5;
|
||||
use test;
|
||||
|
||||
connection root;
|
||||
drop view v1, v2, v3, v4, v5;
|
||||
drop table t1;
|
||||
use test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
|
||||
drop database mysqltest;
|
||||
|
|
16
sql/item.cc
16
sql/item.cc
|
@ -3208,8 +3208,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||
context->last_name_resolution_table,
|
||||
reference,
|
||||
IGNORE_EXCEPT_NON_UNIQUE,
|
||||
!any_privileges &&
|
||||
context->check_privileges,
|
||||
!any_privileges,
|
||||
TRUE)) ==
|
||||
not_found_field)
|
||||
{
|
||||
|
@ -3271,9 +3270,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||
last_name_resolution_table,
|
||||
reference,
|
||||
IGNORE_EXCEPT_NON_UNIQUE,
|
||||
outer_context->
|
||||
check_privileges,
|
||||
TRUE)) !=
|
||||
TRUE, TRUE)) !=
|
||||
not_found_field)
|
||||
{
|
||||
if (from_field)
|
||||
|
@ -3348,7 +3345,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||
context->last_name_resolution_table,
|
||||
reference, REPORT_ALL_ERRORS,
|
||||
!any_privileges &&
|
||||
context->check_privileges, TRUE);
|
||||
TRUE, TRUE);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
@ -3423,7 +3420,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||
We can leave expression substituted from view for next PS/SP rexecution
|
||||
(i.e. do not register this substitution for reverting on cleupup()
|
||||
(register_item_tree_changing())), because this subtree will be
|
||||
fix_field'ed during setup_tables()->setup_ancestor() (i.e. before
|
||||
fix_field'ed during setup_tables()->setup_underlying() (i.e. before
|
||||
all other expressions of query, and references on tables which do
|
||||
not present in query will not make problems.
|
||||
|
||||
|
@ -4518,8 +4515,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||
last_name_resolution_table,
|
||||
reference,
|
||||
IGNORE_EXCEPT_NON_UNIQUE,
|
||||
outer_context->check_privileges,
|
||||
TRUE);
|
||||
TRUE, TRUE);
|
||||
if (! from_field)
|
||||
goto error;
|
||||
if (from_field == view_ref_found)
|
||||
|
@ -5131,7 +5127,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
|
|||
set field_idx properly.
|
||||
*/
|
||||
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
|
||||
0, 0, &field_idx);
|
||||
0, 0, &field_idx, 0);
|
||||
thd->set_query_id= save_set_query_id;
|
||||
triggers= table->triggers;
|
||||
}
|
||||
|
|
|
@ -294,15 +294,15 @@ struct Name_resolution_context: Sql_alloc
|
|||
bool resolve_in_select_list;
|
||||
|
||||
/*
|
||||
When FALSE we do not check columns right of resolving items, used to
|
||||
prevent rights check on underlying tables of view
|
||||
Security context of this name resolution context. It's used for views
|
||||
and is non-zero only if the view is defined with SQL SECURITY DEFINER.
|
||||
*/
|
||||
bool check_privileges;
|
||||
Security_context *security_ctx;
|
||||
|
||||
Name_resolution_context()
|
||||
:outer_context(0), table_list(0), select_lex(0),
|
||||
error_processor_data(0),
|
||||
check_privileges(TRUE)
|
||||
security_ctx(0)
|
||||
{}
|
||||
|
||||
void init()
|
||||
|
|
|
@ -4707,6 +4707,7 @@ Item_func_sp::execute(Field **flp)
|
|||
if (execute(&it))
|
||||
{
|
||||
null_value= 1;
|
||||
context->process_error(current_thd);
|
||||
return 1;
|
||||
}
|
||||
if (!(f= *flp))
|
||||
|
@ -4729,9 +4730,17 @@ Item_func_sp::execute(Item **itp)
|
|||
THD *thd= current_thd;
|
||||
int res= -1;
|
||||
Sub_statement_state statement_state;
|
||||
Security_context *save_ctx;
|
||||
Security_context *save_security_ctx= 0, *save_ctx_func;
|
||||
|
||||
if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx))
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (context->security_ctx)
|
||||
{
|
||||
/* Set view definer security context */
|
||||
save_security_ctx= thd->security_ctx;
|
||||
thd->security_ctx= context->security_ctx;
|
||||
}
|
||||
#endif
|
||||
if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx_func))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
|
@ -4749,9 +4758,14 @@ Item_func_sp::execute(Item **itp)
|
|||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_FAILED_ROUTINE_BREAK_BINLOG,
|
||||
ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
|
||||
|
||||
sp_restore_security_context(thd, save_ctx);
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
sp_restore_security_context(thd, save_ctx_func);
|
||||
error:
|
||||
if (save_security_ctx)
|
||||
thd->security_ctx= save_security_ctx;
|
||||
#else
|
||||
error:
|
||||
#endif
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
@ -4932,8 +4946,20 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
|
|||
bool res;
|
||||
DBUG_ASSERT(fixed == 0);
|
||||
res= Item_func::fix_fields(thd, ref);
|
||||
if (!res)
|
||||
if (!res && thd->lex->view_prepare_mode)
|
||||
{
|
||||
/*
|
||||
Here we check privileges of the stored routine only during view
|
||||
creation, in order to validate the view. A runtime check is perfomed
|
||||
in Item_func_sp::execute(), and this method is not called during
|
||||
context analysis. We do not need to restore the security context
|
||||
changed in find_and_check_access because all view structures created
|
||||
in CREATE VIEW are not used for execution. Notice, that during view
|
||||
creation we do not infer into stored routine bodies and do not check
|
||||
privileges of its statements, which would probably be a good idea
|
||||
especially if the view has SQL SECURITY DEFINER and the used stored
|
||||
procedure has SQL
|
||||
*/
|
||||
Security_context *save_ctx;
|
||||
if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx)))
|
||||
sp_restore_security_context(thd, save_ctx);
|
||||
|
|
|
@ -679,11 +679,11 @@ int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
|
|||
select_result *result);
|
||||
bool mysql_union(THD *thd, LEX *lex, select_result *result,
|
||||
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
|
||||
int mysql_handle_derived(LEX *lex, int (*processor)(THD *thd,
|
||||
LEX *lex,
|
||||
TABLE_LIST *table));
|
||||
int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
|
||||
int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
|
||||
bool mysql_handle_derived(LEX *lex, bool (*processor)(THD *thd,
|
||||
LEX *lex,
|
||||
TABLE_LIST *table));
|
||||
bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
|
||||
bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
|
||||
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
||||
Item ***copy_func, Field **from_field,
|
||||
bool group, bool modify_item,
|
||||
|
@ -793,7 +793,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||
Field *
|
||||
find_field_in_table(THD *thd, TABLE *table, const char *name,
|
||||
uint length, bool check_grants, bool allow_rowid,
|
||||
uint *cached_field_index_ptr);
|
||||
uint *cached_field_index_ptr,
|
||||
Security_context *sctx);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <openssl/des.h>
|
||||
struct st_des_keyblock
|
||||
|
|
|
@ -5210,8 +5210,7 @@ ER_WARN_VIEW_WITHOUT_KEY
|
|||
rus "Обновляемый view не содержит ключа использованных(ой) в нем таблиц(ы)"
|
||||
ukr "View, що оновлюеться, не м╕стить повного ключа таблиц╕(ь), що викор╕стана в ньюому"
|
||||
ER_VIEW_INVALID
|
||||
eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s)"
|
||||
rus "View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÔÏÌÂÃÙ ÉÌÉ ÆÕÎËÃÉÉ"
|
||||
eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them"
|
||||
ER_SP_NO_DROP_SP
|
||||
eng "Can't drop or alter a %s from within another stored routine"
|
||||
ER_SP_GOTO_IN_HNDLR
|
||||
|
|
|
@ -931,6 +931,9 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
|
|||
ACL_USER *acl_user= 0;
|
||||
DBUG_ENTER("acl_getroot_no_password");
|
||||
|
||||
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
|
||||
(host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
|
||||
(user ? user : "(NULL)"), (db ? db : "(NULL)")));
|
||||
sctx->user= user;
|
||||
sctx->host= host;
|
||||
sctx->ip= ip;
|
||||
|
@ -3509,17 +3512,32 @@ end:
|
|||
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
||||
uint show_table, uint number, bool no_errors)
|
||||
{
|
||||
TABLE_LIST *table;
|
||||
TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
|
||||
Security_context *sctx= thd->security_ctx;
|
||||
uint i;
|
||||
DBUG_ENTER("check_grant");
|
||||
DBUG_ASSERT(number > 0);
|
||||
|
||||
/*
|
||||
Iterate tables until first prelocking placeholder (if this query do not
|
||||
have placeholders first_not_own_table is 0)
|
||||
*/
|
||||
for (i= 0, table= tables;
|
||||
table && table != first_not_own_table && i < number;
|
||||
table= table->next_global, i++)
|
||||
{
|
||||
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
|
||||
table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
|
||||
}
|
||||
|
||||
want_access&= ~sctx->master_access;
|
||||
if (!want_access)
|
||||
DBUG_RETURN(0); // ok
|
||||
|
||||
rw_rdlock(&LOCK_grant);
|
||||
for (table= tables; table && number--; table= table->next_global)
|
||||
for (table= tables;
|
||||
table && number-- && table != first_not_own_table;
|
||||
table= table->next_global)
|
||||
{
|
||||
GRANT_TABLE *grant_table;
|
||||
if (!(~table->grant.privilege & want_access) ||
|
||||
|
@ -3529,8 +3547,16 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
|||
It is subquery in the FROM clause. VIEW set table->derived after
|
||||
table opening, but this function always called before table opening.
|
||||
*/
|
||||
table->grant.want_privilege= 0;
|
||||
continue; // Already checked
|
||||
if (!table->referencing_view)
|
||||
{
|
||||
/*
|
||||
If it's a temporary table created for a subquery in the FROM
|
||||
clause, or an INFORMATION_SCHEMA table, drop the request for
|
||||
a privilege.
|
||||
*/
|
||||
table->grant.want_privilege= 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
|
||||
table->db, sctx->priv_user,
|
||||
|
@ -5839,24 +5865,37 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
|||
const char *db, const char *table)
|
||||
{
|
||||
Security_context *sctx= thd->security_ctx;
|
||||
DBUG_ENTER("fill_effective_table_privileges");
|
||||
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', table: `%s`.`%s`",
|
||||
sctx->priv_host, (sctx->ip ? sctx->ip : "(NULL)"),
|
||||
(sctx->priv_user ? sctx->priv_user : "(NULL)"),
|
||||
db, table));
|
||||
/* --skip-grants */
|
||||
if (!initialized)
|
||||
{
|
||||
DBUG_PRINT("info", ("skip grants"));
|
||||
grant->privilege= ~NO_ACCESS; // everything is allowed
|
||||
return;
|
||||
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* global privileges */
|
||||
grant->privilege= sctx->master_access;
|
||||
|
||||
if (!sctx->priv_user)
|
||||
return; // it is slave
|
||||
{
|
||||
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||
DBUG_VOID_RETURN; // it is slave
|
||||
}
|
||||
|
||||
/* db privileges */
|
||||
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
|
||||
|
||||
if (!grant_option)
|
||||
return;
|
||||
{
|
||||
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* table privileges */
|
||||
if (grant->version != grant_version)
|
||||
|
@ -5873,6 +5912,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
|||
{
|
||||
grant->privilege|= grant->grant_table->privs;
|
||||
}
|
||||
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
#else /* NO_EMBEDDED_ACCESS_CHECKS */
|
||||
|
|
|
@ -1971,11 +1971,11 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||
derived/information schema tables and views possible. Thus "counter"
|
||||
may be still zero for prelocked statement...
|
||||
|
||||
NOTE: The above notes may be out of date. Please wait for psergey to
|
||||
NOTE: The above notes may be out of date. Please wait for psergey to
|
||||
document new prelocked behavior.
|
||||
*/
|
||||
|
||||
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
|
||||
|
||||
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
|
||||
thd->lex->sroutines_list.elements)
|
||||
{
|
||||
bool first_no_prelocking, need_prelocking;
|
||||
|
@ -2025,7 +2025,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||
/* VIEW placeholder */
|
||||
(*counter)--;
|
||||
|
||||
/*
|
||||
/*
|
||||
tables->next_global list consists of two parts:
|
||||
1) Query tables and underlying tables of views.
|
||||
2) Tables used by all stored routines that this statement invokes on
|
||||
|
@ -2677,6 +2677,49 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
|
|||
}
|
||||
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/*
|
||||
Check column rights in given security context
|
||||
|
||||
SYNOPSIS
|
||||
check_grant_column_in_sctx()
|
||||
thd thread handler
|
||||
grant grant information structure
|
||||
db db name
|
||||
table table name
|
||||
name column name
|
||||
length column name length
|
||||
check_grants need to check grants
|
||||
sctx 0 or security context
|
||||
|
||||
RETURN
|
||||
FALSE OK
|
||||
TRUE access denied
|
||||
*/
|
||||
|
||||
static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
|
||||
const char *db, const char *table,
|
||||
const char *name, uint length,
|
||||
bool check_grants,
|
||||
Security_context *sctx)
|
||||
{
|
||||
if (!check_grants)
|
||||
return FALSE;
|
||||
Security_context *save_security_ctx= 0;
|
||||
bool res;
|
||||
if (sctx)
|
||||
{
|
||||
save_security_ctx= thd->security_ctx;
|
||||
thd->security_ctx= sctx;
|
||||
}
|
||||
res= check_grant_column(thd, grant, db, table, name, length);
|
||||
if (save_security_ctx)
|
||||
thd->security_ctx= save_security_ctx;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Find a field by name in a view that uses merge algorithm.
|
||||
|
||||
|
@ -2727,11 +2770,11 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
|
|||
*/
|
||||
DBUG_RETURN(((Item_field*) (field_it.item()))->field);
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (check_grants &&
|
||||
check_grant_column(thd, &table_list->grant,
|
||||
table_list->view_db.str,
|
||||
table_list->view_name.str,
|
||||
name, length))
|
||||
if (check_grant_column_in_sctx(thd, &table_list->grant,
|
||||
table_list->view_db.str,
|
||||
table_list->view_name.str, name, length,
|
||||
check_grants,
|
||||
table_list->security_ctx))
|
||||
DBUG_RETURN(WRONG_GRANT);
|
||||
#endif
|
||||
// in PS use own arena or data will be freed after prepare
|
||||
|
@ -2900,7 +2943,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
|
|||
Field *
|
||||
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
||||
bool check_grants, bool allow_rowid,
|
||||
uint *cached_field_index_ptr)
|
||||
uint *cached_field_index_ptr,
|
||||
Security_context *sctx)
|
||||
{
|
||||
Field **field_ptr, *field;
|
||||
uint cached_field_index= *cached_field_index_ptr;
|
||||
|
@ -2909,7 +2953,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
|||
|
||||
/* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
|
||||
if (cached_field_index < table->s->fields &&
|
||||
!my_strcasecmp(system_charset_info,
|
||||
!my_strcasecmp(system_charset_info,
|
||||
table->field[cached_field_index]->field_name, name))
|
||||
field_ptr= table->field + cached_field_index;
|
||||
else if (table->s->name_hash.records)
|
||||
|
@ -2940,9 +2984,10 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
|||
update_field_dependencies(thd, field, table);
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (check_grants && check_grant_column(thd, &table->grant,
|
||||
table->s->db,
|
||||
table->s->table_name, name, length))
|
||||
if (check_grant_column_in_sctx(thd, &table->grant,
|
||||
table->s->db, table->s->table_name,
|
||||
name, length,
|
||||
check_grants, sctx))
|
||||
field= WRONG_GRANT;
|
||||
#endif
|
||||
DBUG_RETURN(field);
|
||||
|
@ -3054,7 +3099,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||
DBUG_ASSERT(table_list->table);
|
||||
if ((fld= find_field_in_table(thd, table_list->table, name, length,
|
||||
check_grants_table, allow_rowid,
|
||||
cached_field_index_ptr)))
|
||||
cached_field_index_ptr,
|
||||
table_list->security_ctx)))
|
||||
*actual_table= table_list;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/* check for views with temporary table algorithm */
|
||||
|
@ -3188,7 +3234,8 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||
test(table_ref->table->
|
||||
grant.want_privilege) &&
|
||||
check_privileges,
|
||||
1, &(item->cached_field_index));
|
||||
1, &(item->cached_field_index),
|
||||
table_ref->security_ctx);
|
||||
else
|
||||
found= find_field_in_table_ref(thd, table_ref, name, item->name,
|
||||
NULL, NULL, length, ref,
|
||||
|
@ -4324,8 +4371,12 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
|
|||
{
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||
{
|
||||
if (table->view && table->effective_algorithm == VIEW_ALGORITHM_MERGE)
|
||||
list= make_leaves_list(list, table->ancestor);
|
||||
if (table->merge_underlying_list)
|
||||
{
|
||||
DBUG_ASSERT(table->view &&
|
||||
table->effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
list= make_leaves_list(list, table->merge_underlying_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
*list= table;
|
||||
|
@ -4425,16 +4476,17 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
|
|||
table_list;
|
||||
table_list= table_list->next_local)
|
||||
{
|
||||
if (table_list->ancestor)
|
||||
if (table_list->merge_underlying_list)
|
||||
{
|
||||
DBUG_ASSERT(table_list->view);
|
||||
DBUG_ASSERT(table_list->view &&
|
||||
table_list->effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
Query_arena *arena= thd->stmt_arena, backup;
|
||||
bool res;
|
||||
if (arena->is_conventional())
|
||||
arena= 0; // For easier test
|
||||
else
|
||||
thd->set_n_backup_active_arena(arena, &backup);
|
||||
res= table_list->setup_ancestor(thd);
|
||||
res= table_list->setup_underlying(thd);
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
if (res)
|
||||
|
|
|
@ -2207,15 +2207,10 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
|
|||
tables_used->view_db.length + 1,
|
||||
HA_CACHE_TBL_NONTRANSACT, 0, 0))
|
||||
DBUG_RETURN(0);
|
||||
{
|
||||
TABLE_COUNTER_TYPE inc= register_tables_from_list(tables_used->ancestor,
|
||||
n + 1,
|
||||
block_table + 1);
|
||||
if (!inc)
|
||||
DBUG_RETURN(0);
|
||||
n+= inc;
|
||||
block_table+= inc;
|
||||
}
|
||||
/*
|
||||
We do not need to register view tables here because they are already
|
||||
present in the global list.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2831,13 +2826,6 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
|
|||
tables_used->view_name.str,
|
||||
tables_used->view_db.str));
|
||||
*tables_type|= HA_CACHE_TBL_NONTRANSACT;
|
||||
{
|
||||
TABLE_COUNTER_TYPE subcount;
|
||||
if (!(subcount= process_and_count_tables(tables_used->ancestor,
|
||||
tables_type)))
|
||||
DBUG_RETURN(0);
|
||||
table_count+= subcount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -414,8 +414,9 @@ bool mysql_multi_delete_prepare(THD *thd)
|
|||
if (!(target_tbl->table= target_tbl->correspondent_table->table))
|
||||
{
|
||||
DBUG_ASSERT(target_tbl->correspondent_table->view &&
|
||||
target_tbl->correspondent_table->ancestor &&
|
||||
target_tbl->correspondent_table->ancestor->next_local);
|
||||
target_tbl->correspondent_table->merge_underlying_list &&
|
||||
target_tbl->correspondent_table->merge_underlying_list->
|
||||
next_local);
|
||||
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
|
||||
target_tbl->correspondent_table->view_db.str,
|
||||
target_tbl->correspondent_table->view_name.str);
|
||||
|
|
|
@ -35,14 +35,14 @@
|
|||
processor procedure of derived table processing
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error and error message given
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
int
|
||||
mysql_handle_derived(LEX *lex, int (*processor)(THD*, LEX*, TABLE_LIST*))
|
||||
bool
|
||||
mysql_handle_derived(LEX *lex, bool (*processor)(THD*, LEX*, TABLE_LIST*))
|
||||
{
|
||||
int res= 0;
|
||||
bool res= FALSE;
|
||||
if (lex->derived_tables)
|
||||
{
|
||||
lex->thd->derived_tables_processing= TRUE;
|
||||
|
@ -95,16 +95,16 @@ out:
|
|||
close_thread_tables()
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error and an error message was given
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= orig_table_list->derived;
|
||||
int res= 0;
|
||||
ulonglong create_options;
|
||||
DBUG_ENTER("mysql_derived_prepare");
|
||||
bool res= FALSE;
|
||||
if (unit)
|
||||
{
|
||||
SELECT_LEX *first_select= unit->first_select();
|
||||
|
@ -118,7 +118,7 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
|||
sl->context.outer_context= 0;
|
||||
|
||||
if (!(derived_result= new select_union))
|
||||
DBUG_RETURN(1); // out of memory
|
||||
DBUG_RETURN(TRUE); // out of memory
|
||||
|
||||
// st_select_lex_unit::prepare correctly work for single select
|
||||
if ((res= unit->prepare(thd, derived_result, 0)))
|
||||
|
@ -184,7 +184,10 @@ exit:
|
|||
table->derived_select_number= first_select->select_number;
|
||||
table->s->tmp_table= TMP_TABLE;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table->grant.privilege= SELECT_ACL;
|
||||
if (orig_table_list->referencing_view)
|
||||
table->grant= orig_table_list->grant;
|
||||
else
|
||||
table->grant.privilege= SELECT_ACL;
|
||||
#endif
|
||||
orig_table_list->db= (char *)"";
|
||||
orig_table_list->db_length= 0;
|
||||
|
@ -195,8 +198,8 @@ exit:
|
|||
thd->derived_tables= table;
|
||||
}
|
||||
}
|
||||
else if (orig_table_list->ancestor)
|
||||
orig_table_list->set_ancestor();
|
||||
else if (orig_table_list->merge_underlying_list)
|
||||
orig_table_list->set_underlying_merge();
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
@ -220,15 +223,15 @@ exit:
|
|||
Due to evaluation of LIMIT clause it can not be used at prepared stage.
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error and an error message was given
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
{
|
||||
TABLE *table= orig_table_list->table;
|
||||
SELECT_LEX_UNIT *unit= orig_table_list->derived;
|
||||
int res= 0;
|
||||
bool res= FALSE;
|
||||
|
||||
/*check that table creation pass without problem and it is derived table */
|
||||
if (table && unit)
|
||||
|
@ -271,7 +274,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
|||
there were no derived tables
|
||||
*/
|
||||
if (derived_result->flush())
|
||||
res= 1;
|
||||
res= TRUE;
|
||||
|
||||
if (!lex->describe)
|
||||
unit->cleanup();
|
||||
|
|
|
@ -800,6 +800,11 @@ typedef struct st_lex
|
|||
*/
|
||||
uint table_count;
|
||||
uint8 describe;
|
||||
/*
|
||||
A flag that indicates what kinds of derived tables are present in the
|
||||
query (0 if no derived tables, otherwise a combination of flags
|
||||
DERIVED_SUBQUERY and DERIVED_VIEW.
|
||||
*/
|
||||
uint8 derived_tables;
|
||||
uint8 create_view_algorithm;
|
||||
uint8 create_view_check;
|
||||
|
|
|
@ -5026,8 +5026,13 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
|
|||
{
|
||||
uint found=0;
|
||||
ulong found_access=0;
|
||||
TABLE_LIST *org_tables=tables;
|
||||
for (; tables; tables= tables->next_global)
|
||||
TABLE_LIST *org_tables= tables;
|
||||
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
|
||||
/*
|
||||
Iterate tables until first prelocking placeholder (if this query do not
|
||||
have placeholders first_not_own_table is 0)
|
||||
*/
|
||||
for (; tables && tables != first_not_own_table; tables= tables->next_global)
|
||||
{
|
||||
if (tables->schema_table &&
|
||||
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
|
||||
|
@ -5038,6 +5043,11 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
|
|||
information_schema_name.str);
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
Register access for view underlying table.
|
||||
Remove SHOW_VIEW_ACL, because it will be checked during making view
|
||||
*/
|
||||
tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
|
||||
if (tables->derived || tables->schema_table || tables->belong_to_view ||
|
||||
(tables->table && (int)tables->table->s->tmp_table) ||
|
||||
my_tz_check_n_skip_implicit_tables(&tables,
|
||||
|
|
|
@ -1158,6 +1158,7 @@ static int mysql_test_update(Prepared_statement *stmt,
|
|||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table_list->grant.want_privilege= want_privilege;
|
||||
table_list->table->grant.want_privilege= want_privilege;
|
||||
table_list->register_want_access(want_privilege);
|
||||
#endif
|
||||
thd->lex->select_lex.no_wrap_view_item= TRUE;
|
||||
res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
|
||||
|
@ -1169,6 +1170,7 @@ static int mysql_test_update(Prepared_statement *stmt,
|
|||
table_list->grant.want_privilege=
|
||||
table_list->table->grant.want_privilege=
|
||||
(SELECT_ACL & ~table_list->table->grant.privilege);
|
||||
table_list->register_want_access(SELECT_ACL);
|
||||
#endif
|
||||
if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
|
||||
goto error;
|
||||
|
|
|
@ -195,6 +195,7 @@ int mysql_update(THD *thd,
|
|||
/* Check the fields we are going to modify */
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
|
||||
table_list->register_want_access(want_privilege);
|
||||
#endif
|
||||
if (setup_fields_with_no_wrap(thd, 0, fields, 1, 0, 0))
|
||||
DBUG_RETURN(1); /* purecov: inspected */
|
||||
|
@ -584,6 +585,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
|||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table_list->grant.want_privilege= table->grant.want_privilege=
|
||||
(SELECT_ACL & ~table->grant.privilege);
|
||||
table_list->register_want_access(SELECT_ACL);
|
||||
#endif
|
||||
|
||||
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
|
||||
|
|
115
sql/sql_view.cc
115
sql/sql_view.cc
|
@ -721,6 +721,7 @@ loop_out:
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
read VIEW .frm and create structures
|
||||
|
||||
|
@ -737,11 +738,26 @@ loop_out:
|
|||
my_bool
|
||||
mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
DBUG_ENTER("mysql_make_view");
|
||||
DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name));
|
||||
|
||||
if (table->view)
|
||||
{
|
||||
/*
|
||||
It's an execution of a PS/SP and the view has already been unfolded
|
||||
into a list of used tables. Now we only need to update the information
|
||||
about granted privileges in the view tables with the actual data
|
||||
stored in MySQL privilege system. We don't need to restore the
|
||||
required privileges (by calling register_want_access) because they has
|
||||
not changed since PREPARE or the previous execution: the only case
|
||||
when this information is changed is execution of UPDATE on a view, but
|
||||
the original want_access is restored in its end.
|
||||
*/
|
||||
if (!table->prelocking_placeholder && table->prepare_security(thd))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_PRINT("info",
|
||||
("VIEW %s.%s is already processed on previous PS/SP execution",
|
||||
table->view_db.str, table->view_name.str));
|
||||
|
@ -749,7 +765,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
}
|
||||
|
||||
SELECT_LEX *end;
|
||||
THD *thd= current_thd;
|
||||
LEX *old_lex= thd->lex, *lex;
|
||||
SELECT_LEX *view_select;
|
||||
int res= 0;
|
||||
|
@ -768,7 +783,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
if (!table->timestamp.str)
|
||||
table->timestamp.str= table->timestamp_buffer;
|
||||
/* prepare default values for old format */
|
||||
table->view_suid= 1;
|
||||
table->view_suid= TRUE;
|
||||
table->definer.user.str= table->definer.host.str= 0;
|
||||
table->definer.user.length= table->definer.host.length= 0;
|
||||
|
||||
|
@ -879,6 +894,10 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
goto err;
|
||||
}
|
||||
|
||||
|
||||
if (!(table->view_tables=
|
||||
(List<TABLE_LIST>*) new(thd->mem_root) List<TABLE_LIST>))
|
||||
goto err;
|
||||
/*
|
||||
mark to avoid temporary table using and put view reference and find
|
||||
last view table
|
||||
|
@ -889,6 +908,22 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
{
|
||||
tbl->skip_temporary= 1;
|
||||
tbl->belong_to_view= top_view;
|
||||
tbl->referencing_view= table;
|
||||
/*
|
||||
First we fill want_privilege with SELECT_ACL (this is needed for the
|
||||
tables which belongs to view subqueries and temporary table views,
|
||||
then for the merged view underlying tables we will set wanted
|
||||
privileges of top_view
|
||||
*/
|
||||
tbl->grant.want_privilege= SELECT_ACL;
|
||||
/*
|
||||
After unfolding the view we lose the list of tables referenced in it
|
||||
(we will have only a list of underlying tables in case of MERGE
|
||||
algorithm, which does not include the tables referenced from
|
||||
subqueries used in view definition).
|
||||
Let's build a list of all tables referenced in the view.
|
||||
*/
|
||||
table->view_tables->push_back(tbl);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -913,16 +948,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
table->next_global= view_tables;
|
||||
}
|
||||
|
||||
/*
|
||||
Let us set proper lock type for tables of the view's main select
|
||||
since we may want to perform update or insert on view. This won't
|
||||
work for view containing union. But this is ok since we don't
|
||||
allow insert and update on such views anyway.
|
||||
*/
|
||||
if (!lex->select_lex.next_select())
|
||||
for (tbl= lex->select_lex.get_table_list(); tbl; tbl= tbl->next_local)
|
||||
tbl->lock_type= table->lock_type;
|
||||
|
||||
/*
|
||||
If we are opening this view as part of implicit LOCK TABLES, then
|
||||
this view serves as simple placeholder and we should not continue
|
||||
|
@ -931,7 +956,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
if (table->prelocking_placeholder)
|
||||
goto ok2;
|
||||
|
||||
old_lex->derived_tables|= DERIVED_VIEW;
|
||||
old_lex->derived_tables|= (DERIVED_VIEW | lex->derived_tables);
|
||||
|
||||
/* move SQL_NO_CACHE & Co to whole query */
|
||||
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
|
||||
|
@ -940,6 +965,37 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
if (view_select->options & OPTION_TO_QUERY_CACHE)
|
||||
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
|
||||
|
||||
if (table->view_suid)
|
||||
{
|
||||
/*
|
||||
Prepare a security context to check underlying objects of the view
|
||||
*/
|
||||
Security_context *save_security_ctx= thd->security_ctx;
|
||||
if (!(table->view_sctx= (Security_context *)
|
||||
thd->stmt_arena->alloc(sizeof(Security_context))))
|
||||
goto err;
|
||||
/* Assign the context to the tables referenced in the view */
|
||||
for (tbl= view_tables; tbl; tbl= tbl->next_global)
|
||||
tbl->security_ctx= table->view_sctx;
|
||||
/* assign security context to SELECT name resolution contexts of view */
|
||||
for(SELECT_LEX *sl= lex->all_selects_list;
|
||||
sl;
|
||||
sl= sl->next_select_in_list())
|
||||
sl->context.security_ctx= table->view_sctx;
|
||||
}
|
||||
|
||||
/*
|
||||
Setup an error processor to hide error messages issued by stored
|
||||
routines referenced in the view
|
||||
*/
|
||||
for (SELECT_LEX *sl= lex->all_selects_list;
|
||||
sl;
|
||||
sl= sl->next_select_in_list())
|
||||
{
|
||||
sl->context.error_processor= &view_error_processor;
|
||||
sl->context.error_processor_data= (void *)table;
|
||||
}
|
||||
|
||||
/*
|
||||
check MERGE algorithm ability
|
||||
- algorithm is not explicit TEMPORARY TABLE
|
||||
|
@ -961,24 +1017,28 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
table->updatable= (table->updatable_view != 0);
|
||||
table->effective_with_check=
|
||||
old_lex->get_effective_with_check(table);
|
||||
table->merge_underlying_list= view_tables;
|
||||
/*
|
||||
Let us set proper lock type for tables of the view's main select
|
||||
since we may want to perform update or insert on view. This won't
|
||||
work for view containing union. But this is ok since we don't
|
||||
allow insert and update on such views anyway.
|
||||
|
||||
Also we fill correct wanted privileges.
|
||||
*/
|
||||
for (tbl= table->merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
tbl->lock_type= table->lock_type;
|
||||
tbl->grant.want_privilege= top_view->grant.orig_want_privilege;
|
||||
}
|
||||
|
||||
/* prepare view context */
|
||||
lex->select_lex.context.resolve_in_table_list_only(table->ancestor=
|
||||
view_tables);
|
||||
lex->select_lex.context.resolve_in_table_list_only(view_tables);
|
||||
lex->select_lex.context.outer_context= 0;
|
||||
lex->select_lex.context.select_lex= table->select_lex;
|
||||
lex->select_lex.select_n_having_items+=
|
||||
table->select_lex->select_n_having_items;
|
||||
|
||||
/* do not check privileges & hide errors for view underlyings */
|
||||
for (SELECT_LEX *sl= lex->all_selects_list;
|
||||
sl;
|
||||
sl= sl->next_select_in_list())
|
||||
{
|
||||
sl->context.check_privileges= FALSE;
|
||||
sl->context.error_processor= &view_error_processor;
|
||||
sl->context.error_processor_data= (void *)table;
|
||||
}
|
||||
/*
|
||||
Tables of the main select of the view should be marked as belonging
|
||||
to the same select as original view (again we can use LEX::select_lex
|
||||
|
@ -1011,7 +1071,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||
}
|
||||
}
|
||||
|
||||
/* Store WHERE clause for post-processing in setup_ancestor */
|
||||
/* Store WHERE clause for post-processing in setup_underlying */
|
||||
table->where= view_select->where;
|
||||
/*
|
||||
Add subqueries units to SELECT into which we merging current view.
|
||||
|
@ -1077,6 +1137,11 @@ ok2:
|
|||
if (!old_lex->time_zone_tables_used && thd->lex->time_zone_tables_used)
|
||||
old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used;
|
||||
thd->lex= old_lex;
|
||||
if (!table->prelocking_placeholder && table->prepare_security(thd))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
|
|
233
sql/table.cc
233
sql/table.cc
|
@ -1798,41 +1798,43 @@ void st_table_list::calc_md5(char *buffer)
|
|||
|
||||
|
||||
/*
|
||||
set ancestor TABLE for table place holder of VIEW
|
||||
set underlying TABLE for table place holder of VIEW
|
||||
|
||||
DESCRIPTION
|
||||
Replace all views that only uses one table with the table itself.
|
||||
This allows us to treat the view as a simple table and even update
|
||||
it
|
||||
it (it is a kind of optimisation)
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::set_ancestor()
|
||||
st_table_list::set_underlying_merge()
|
||||
*/
|
||||
|
||||
void st_table_list::set_ancestor()
|
||||
void st_table_list::set_underlying_merge()
|
||||
{
|
||||
TABLE_LIST *tbl;
|
||||
|
||||
if ((tbl= ancestor))
|
||||
if ((tbl= merge_underlying_list))
|
||||
{
|
||||
/* This is a view. Process all tables of view */
|
||||
DBUG_ASSERT(view);
|
||||
DBUG_ASSERT(view && effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
do
|
||||
{
|
||||
if (tbl->ancestor) // This is a view
|
||||
if (tbl->merge_underlying_list) // This is a view
|
||||
{
|
||||
DBUG_ASSERT(tbl->view &&
|
||||
tbl->effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
/*
|
||||
This is the only case where set_ancestor is called on an object
|
||||
that may not be a view (in which case ancestor is 0)
|
||||
*/
|
||||
tbl->ancestor->set_ancestor();
|
||||
tbl->merge_underlying_list->set_underlying_merge();
|
||||
}
|
||||
} while ((tbl= tbl->next_local));
|
||||
|
||||
if (!multitable_view)
|
||||
{
|
||||
table= ancestor->table;
|
||||
schema_table= ancestor->schema_table;
|
||||
table= merge_underlying_list->table;
|
||||
schema_table= merge_underlying_list->schema_table;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1842,12 +1844,9 @@ void st_table_list::set_ancestor()
|
|||
setup fields of placeholder of merged VIEW
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::setup_ancestor()
|
||||
st_table_list::setup_underlying()
|
||||
thd - thread handler
|
||||
|
||||
NOTES
|
||||
ancestor is list of tables and views used by view (underlying tables/views)
|
||||
|
||||
DESCRIPTION
|
||||
It is:
|
||||
- preparing translation table for view columns
|
||||
|
@ -1858,10 +1857,11 @@ void st_table_list::set_ancestor()
|
|||
TRUE - error
|
||||
*/
|
||||
|
||||
bool st_table_list::setup_ancestor(THD *thd)
|
||||
bool st_table_list::setup_underlying(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::setup_ancestor");
|
||||
if (!field_translation)
|
||||
DBUG_ENTER("st_table_list::setup_underlying");
|
||||
|
||||
if (!field_translation && merge_underlying_list)
|
||||
{
|
||||
Field_translator *transl;
|
||||
SELECT_LEX *select= &view->select_lex;
|
||||
|
@ -1875,10 +1875,10 @@ bool st_table_list::setup_ancestor(THD *thd)
|
|||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
for (tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->ancestor &&
|
||||
tbl->setup_ancestor(thd))
|
||||
if (tbl->merge_underlying_list &&
|
||||
tbl->setup_underlying(thd))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
@ -1941,7 +1941,7 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
|
|||
{
|
||||
DBUG_ENTER("st_table_list::prep_where");
|
||||
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->view && tbl->prep_where(thd, conds, no_where_clause))
|
||||
{
|
||||
|
@ -2023,7 +2023,7 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
|
|||
{
|
||||
DBUG_ENTER("st_table_list::prep_check_option");
|
||||
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
/* see comment of check_opt_type parameter */
|
||||
if (tbl->view &&
|
||||
|
@ -2046,7 +2046,7 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
|
|||
}
|
||||
if (check_opt_type == VIEW_CHECK_CASCADED)
|
||||
{
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->check_option)
|
||||
item= and_conds(item, tbl->check_option);
|
||||
|
@ -2085,16 +2085,21 @@ void st_table_list::hide_view_error(THD *thd)
|
|||
{
|
||||
/* Hide "Unknown column" or "Unknown function" error */
|
||||
if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
|
||||
thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
|
||||
thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
|
||||
thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
|
||||
thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR)
|
||||
{
|
||||
TABLE_LIST *top= top_table();
|
||||
thd->clear_error();
|
||||
my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str);
|
||||
my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
|
||||
}
|
||||
else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
|
||||
{
|
||||
TABLE_LIST *top= top_table();
|
||||
thd->clear_error();
|
||||
// TODO: make correct error message
|
||||
my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str);
|
||||
my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0),
|
||||
top->view_db.str, top->view_name.str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2115,10 +2120,10 @@ void st_table_list::hide_view_error(THD *thd)
|
|||
st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
|
||||
{
|
||||
/* is this real table and table which we are looking for? */
|
||||
if (table == table_to_find && ancestor == 0)
|
||||
if (table == table_to_find && merge_underlying_list == 0)
|
||||
return this;
|
||||
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
TABLE_LIST *result;
|
||||
if ((result= tbl->find_underlying_table(table_to_find)))
|
||||
|
@ -2201,7 +2206,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
|
|||
bool st_table_list::check_single_table(st_table_list **table, table_map map,
|
||||
st_table_list *view)
|
||||
{
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->table)
|
||||
{
|
||||
|
@ -2243,8 +2248,8 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
|
|||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(view && ancestor);
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
DBUG_ASSERT(view && merge_underlying_list);
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
if (tbl->set_insert_values(mem_root))
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -2390,6 +2395,159 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Register access mode which we need for underlying tables
|
||||
|
||||
SYNOPSIS
|
||||
register_want_access()
|
||||
want_access Acess which we require
|
||||
*/
|
||||
|
||||
void st_table_list::register_want_access(ulong want_access)
|
||||
{
|
||||
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
|
||||
want_access&= ~SHOW_VIEW_ACL;
|
||||
if (belong_to_view)
|
||||
{
|
||||
grant.want_privilege= want_access;
|
||||
if (table)
|
||||
table->grant.want_privilege= want_access;
|
||||
}
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
tbl->register_want_access(want_access);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Load security context infoemation for this view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prepare_view_securety_context()
|
||||
thd [in] thread handler
|
||||
|
||||
RETURN
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
bool st_table_list::prepare_view_securety_context(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::prepare_view_securety_context");
|
||||
DBUG_PRINT("enter", ("table: %s", alias));
|
||||
|
||||
DBUG_ASSERT(!prelocking_placeholder && view);
|
||||
if (view_suid)
|
||||
{
|
||||
DBUG_PRINT("info", ("This table is suid view => load contest"));
|
||||
DBUG_ASSERT(view && view_sctx);
|
||||
if (acl_getroot_no_password(view_sctx,
|
||||
definer.user.str,
|
||||
definer.host.str,
|
||||
definer.host.str,
|
||||
thd->db))
|
||||
{
|
||||
my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Find security context of current view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::find_view_security_context()
|
||||
thd [in] thread handler
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *st_table_list::find_view_security_context(THD *thd)
|
||||
{
|
||||
Security_context *sctx;
|
||||
TABLE_LIST *upper_view= this;
|
||||
DBUG_ENTER("st_table_list::find_view_security_context");
|
||||
|
||||
DBUG_ASSERT(view);
|
||||
while (upper_view && !upper_view->view_suid)
|
||||
{
|
||||
DBUG_ASSERT(!upper_view->prelocking_placeholder);
|
||||
upper_view= upper_view->referencing_view;
|
||||
}
|
||||
if (upper_view)
|
||||
{
|
||||
DBUG_PRINT("info", ("Securety context of view %s will be used",
|
||||
upper_view->alias));
|
||||
sctx= upper_view->view_sctx;
|
||||
DBUG_ASSERT(sctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("info", ("Current global context will be used"));
|
||||
sctx= thd->security_ctx;
|
||||
}
|
||||
DBUG_RETURN(sctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Prepare security context and load underlying tables priveleges for view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prepare_security()
|
||||
thd [in] thread handler
|
||||
|
||||
RETURN
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
bool st_table_list::prepare_security(THD *thd)
|
||||
{
|
||||
List_iterator_fast<TABLE_LIST> tb(*view_tables);
|
||||
TABLE_LIST *tbl;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *save_security_ctx= thd->security_ctx;
|
||||
DBUG_ENTER("st_table_list::prepare_security");
|
||||
|
||||
DBUG_ASSERT(!prelocking_placeholder);
|
||||
if (prepare_view_securety_context(thd))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
thd->security_ctx= find_view_security_context(thd);
|
||||
while ((tbl= tb++))
|
||||
{
|
||||
DBUG_ASSERT(tbl->referencing_view);
|
||||
char *db, *table_name;
|
||||
if (tbl->view)
|
||||
{
|
||||
db= tbl->view_db.str;
|
||||
table_name= tbl->view_name.str;
|
||||
}
|
||||
else
|
||||
{
|
||||
db= tbl->db;
|
||||
table_name= tbl->table_name;
|
||||
}
|
||||
fill_effective_table_privileges(thd, &tbl->grant, db, table_name);
|
||||
if (tbl->table)
|
||||
tbl->table->grant= grant;
|
||||
}
|
||||
thd->security_ctx= save_security_ctx;
|
||||
DBUG_RETURN(FALSE);
|
||||
#else
|
||||
while ((tbl= tb++))
|
||||
tbl->grant.privilege= ~NO_ACCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Natural_join_column::Natural_join_column(Field_translator *field_param,
|
||||
TABLE_LIST *tab)
|
||||
{
|
||||
|
@ -2498,6 +2656,9 @@ Natural_join_column::check_grants(THD *thd, const char *name, uint length)
|
|||
GRANT_INFO *grant;
|
||||
const char *db_name;
|
||||
const char *table_name;
|
||||
Security_context *save_security_ctx= 0;
|
||||
Security_context *new_sctx= table_ref->security_ctx;
|
||||
bool res;
|
||||
|
||||
if (view_field)
|
||||
{
|
||||
|
@ -2514,7 +2675,15 @@ Natural_join_column::check_grants(THD *thd, const char *name, uint length)
|
|||
table_name= table_ref->table->s->table_name;
|
||||
}
|
||||
|
||||
return check_grant_column(thd, grant, db_name, table_name, name, length);
|
||||
if (new_sctx)
|
||||
{
|
||||
save_security_ctx= thd->security_ctx;
|
||||
thd->security_ctx= new_sctx;
|
||||
}
|
||||
res= check_grant_column(thd, grant, db_name, table_name, name, length);
|
||||
if (save_security_ctx)
|
||||
thd->security_ctx= save_security_ctx;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
48
sql/table.h
48
sql/table.h
|
@ -22,6 +22,7 @@ class GRANT_TABLE;
|
|||
class st_select_lex_unit;
|
||||
class st_select_lex;
|
||||
class COND_EQUAL;
|
||||
class Security_context;
|
||||
|
||||
/* Order clause list element */
|
||||
|
||||
|
@ -47,6 +48,11 @@ typedef struct st_grant_info
|
|||
uint version;
|
||||
ulong privilege;
|
||||
ulong want_privilege;
|
||||
/*
|
||||
Stores the requested access acl of top level tables list. Is used to
|
||||
check access rights to the underlying tables of a view.
|
||||
*/
|
||||
ulong orig_want_privilege;
|
||||
} GRANT_INFO;
|
||||
|
||||
enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2,
|
||||
|
@ -359,7 +365,6 @@ typedef struct st_schema_table
|
|||
#define VIEW_CHECK_SKIP 2
|
||||
|
||||
struct st_lex;
|
||||
struct st_table_list;
|
||||
class select_union;
|
||||
class TMP_TABLE_PARAM;
|
||||
|
||||
|
@ -525,10 +530,35 @@ typedef struct st_table_list
|
|||
Field_translator *field_translation; /* array of VIEW fields */
|
||||
/* pointer to element after last one in translation table above */
|
||||
Field_translator *field_translation_end;
|
||||
/* list of ancestor(s) of this table (underlying table(s)/view(s) */
|
||||
st_table_list *ancestor;
|
||||
/*
|
||||
List (based on next_local) of underlying tables of this view. I.e. it
|
||||
does not include the tables of subqueries used in the view. Is set only
|
||||
for merged views.
|
||||
*/
|
||||
st_table_list *merge_underlying_list;
|
||||
/*
|
||||
- 0 for base tables
|
||||
- in case of the view it is the list of all (not only underlying
|
||||
tables but also used in subquery ones) tables of the view.
|
||||
*/
|
||||
List<st_table_list> *view_tables;
|
||||
/* most upper view this table belongs to */
|
||||
st_table_list *belong_to_view;
|
||||
/*
|
||||
The view directly referencing this table
|
||||
(non-zero only for merged underlying tables of a view).
|
||||
*/
|
||||
st_table_list *referencing_view;
|
||||
/*
|
||||
security context (non-zero only for tables which belong
|
||||
to view with SQL SEURITY DEFINER)
|
||||
*/
|
||||
Security_context *security_ctx;
|
||||
/*
|
||||
this view security context (non-zero only for views with
|
||||
SQL SEURITY DEFINER)
|
||||
*/
|
||||
Security_context *view_sctx;
|
||||
/*
|
||||
List of all base tables local to a subquery including all view
|
||||
tables. Unlike 'next_local', this in this list views are *not*
|
||||
|
@ -595,9 +625,9 @@ typedef struct st_table_list
|
|||
bool prelocking_placeholder;
|
||||
|
||||
void calc_md5(char *buffer);
|
||||
void set_ancestor();
|
||||
void set_underlying_merge();
|
||||
int view_check_option(THD *thd, bool ignore_failure);
|
||||
bool setup_ancestor(THD *thd);
|
||||
bool setup_underlying(THD *thd);
|
||||
void cleanup_items();
|
||||
bool placeholder() {return derived || view; }
|
||||
void print(THD *thd, String *str);
|
||||
|
@ -625,6 +655,14 @@ typedef struct st_table_list
|
|||
return prep_where(thd, conds, no_where_clause);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void register_want_access(ulong want_access);
|
||||
bool prepare_security(THD *thd);
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *find_view_security_context(THD *thd);
|
||||
bool prepare_view_securety_context(THD *thd);
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool prep_check_option(THD *thd, uint8 check_opt_type);
|
||||
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
|
||||
|
|
Loading…
Add table
Reference in a new issue