Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-5.0
into sanja.is.com.ua:/home/bell/mysql/bk/work-owner7-5.0
This commit is contained in:
commit
6143c6543e
@ -648,21 +648,21 @@ select table_name from information_schema.views
|
|||||||
where table_schema='test';
|
where table_schema='test';
|
||||||
table_name
|
table_name
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1356 View 'test.v2' 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)
|
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
|
select table_name from information_schema.views
|
||||||
where table_schema='test';
|
where table_schema='test';
|
||||||
table_name
|
table_name
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1356 View 'test.v2' 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)
|
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
|
select column_name from information_schema.columns
|
||||||
where table_schema='test';
|
where table_schema='test';
|
||||||
column_name
|
column_name
|
||||||
f1
|
f1
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1356 View 'test.v2' 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)
|
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';
|
select index_name from information_schema.statistics where table_schema='test';
|
||||||
index_name
|
index_name
|
||||||
f1_key
|
f1_key
|
||||||
|
@ -1032,7 +1032,7 @@ a f8()
|
|||||||
3 1
|
3 1
|
||||||
drop function f1|
|
drop function f1|
|
||||||
select * from v1|
|
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
|
create function f1() returns int
|
||||||
return (select sum(data) from t1) + (select sum(data) from v1)|
|
return (select sum(data) from t1) + (select sum(data) from v1)|
|
||||||
drop function f1|
|
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` (
|
CREATE TABLE `t1` (
|
||||||
a int not null auto_increment,
|
a int not null auto_increment,
|
||||||
`pseudo` varchar(35) character set latin2 NOT NULL default '',
|
`pseudo` varchar(35) character set latin2 NOT NULL default '',
|
||||||
|
@ -574,10 +574,10 @@ create view v1 as select * from t1;
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
create table t1 (col1 char(5),newcol2 char(5));
|
create table t1 (col1 char(5),newcol2 char(5));
|
||||||
insert into v1 values('a','aa');
|
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;
|
drop table t1;
|
||||||
select * from v1;
|
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;
|
drop view v1;
|
||||||
create view v1 (a,a) as select 'a','a';
|
create view v1 (a,a) as select 'a','a';
|
||||||
ERROR 42S21: Duplicate column name 'a'
|
ERROR 42S21: Duplicate column name 'a'
|
||||||
@ -809,11 +809,11 @@ create table t1 (s1 int);
|
|||||||
create view v1 as select x1() from t1;
|
create view v1 as select x1() from t1;
|
||||||
drop function x1;
|
drop function x1;
|
||||||
select * from v1;
|
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;
|
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
|
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
|
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 view v1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1;
|
create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1;
|
||||||
@ -1360,7 +1360,7 @@ test.t1 check status OK
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
check table v1;
|
check table v1;
|
||||||
Table Op Msg_type Msg_text
|
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;
|
drop view v1;
|
||||||
create table t1 (a int);
|
create table t1 (a int);
|
||||||
create table t2 (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;
|
DROP TABLE t1;
|
||||||
CHECK TABLE v1, v2, v3, v4, v5, v6;
|
CHECK TABLE v1, v2, v3, v4, v5, v6;
|
||||||
Table Op Msg_type Msg_text
|
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.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.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
|
test.v6 check status OK
|
||||||
drop view v1, v2, v3, v4, v5, v6;
|
drop view v1, v2, v3, v4, v5, v6;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
@ -1908,11 +1908,11 @@ CREATE VIEW v6 AS SELECT f2() FROM t3;
|
|||||||
drop function f1;
|
drop function f1;
|
||||||
CHECK TABLE v1, v2, v3, v4, v5, v6;
|
CHECK TABLE v1, v2, v3, v4, v5, v6;
|
||||||
Table Op Msg_type Msg_text
|
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.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.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
|
test.v6 check status OK
|
||||||
create function f1 () returns int return (select max(col1) from t1);
|
create function f1 () returns int return (select max(col1) from t1);
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
@ -2154,7 +2154,7 @@ Field Type Null Key Default Extra
|
|||||||
f4 char(5) YES NULL
|
f4 char(5) YES NULL
|
||||||
ALTER TABLE t1 CHANGE COLUMN f4 f4x CHAR(5);
|
ALTER TABLE t1 CHANGE COLUMN f4 f4x CHAR(5);
|
||||||
DESCRIBE v1;
|
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 TABLE t1;
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
create table t1 (f1 char);
|
create table t1 (f1 char);
|
||||||
|
@ -305,5 +305,172 @@ create table mysqltest.t1 (a int);
|
|||||||
grant all privileges on mysqltest.* to mysqltest_1@localhost;
|
grant all privileges on mysqltest.* to mysqltest_1@localhost;
|
||||||
use mysqltest;
|
use mysqltest;
|
||||||
create view v1 as select * from t1;
|
create view v1 as select * from t1;
|
||||||
|
use test;
|
||||||
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
|
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
|
||||||
drop database mysqltest;
|
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
|
--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
|
--enable_warnings
|
||||||
|
|
||||||
CREATE TABLE `t1` (
|
CREATE TABLE `t1` (
|
||||||
|
@ -401,8 +401,221 @@ grant all privileges on mysqltest.* to mysqltest_1@localhost;
|
|||||||
connection user1;
|
connection user1;
|
||||||
use mysqltest;
|
use mysqltest;
|
||||||
create view v1 as select * from t1;
|
create view v1 as select * from t1;
|
||||||
|
use test;
|
||||||
|
|
||||||
connection root;
|
connection root;
|
||||||
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
|
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
|
||||||
drop database mysqltest;
|
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
@ -3234,8 +3234,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
context->last_name_resolution_table,
|
context->last_name_resolution_table,
|
||||||
reference,
|
reference,
|
||||||
IGNORE_EXCEPT_NON_UNIQUE,
|
IGNORE_EXCEPT_NON_UNIQUE,
|
||||||
!any_privileges &&
|
!any_privileges,
|
||||||
context->check_privileges,
|
|
||||||
TRUE)) ==
|
TRUE)) ==
|
||||||
not_found_field)
|
not_found_field)
|
||||||
{
|
{
|
||||||
@ -3297,9 +3296,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
last_name_resolution_table,
|
last_name_resolution_table,
|
||||||
reference,
|
reference,
|
||||||
IGNORE_EXCEPT_NON_UNIQUE,
|
IGNORE_EXCEPT_NON_UNIQUE,
|
||||||
outer_context->
|
TRUE, TRUE)) !=
|
||||||
check_privileges,
|
|
||||||
TRUE)) !=
|
|
||||||
not_found_field)
|
not_found_field)
|
||||||
{
|
{
|
||||||
if (from_field)
|
if (from_field)
|
||||||
@ -3374,7 +3371,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
context->last_name_resolution_table,
|
context->last_name_resolution_table,
|
||||||
reference, REPORT_ALL_ERRORS,
|
reference, REPORT_ALL_ERRORS,
|
||||||
!any_privileges &&
|
!any_privileges &&
|
||||||
context->check_privileges, TRUE);
|
TRUE, TRUE);
|
||||||
}
|
}
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -3449,7 +3446,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
We can leave expression substituted from view for next PS/SP rexecution
|
We can leave expression substituted from view for next PS/SP rexecution
|
||||||
(i.e. do not register this substitution for reverting on cleupup()
|
(i.e. do not register this substitution for reverting on cleupup()
|
||||||
(register_item_tree_changing())), because this subtree will be
|
(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
|
all other expressions of query, and references on tables which do
|
||||||
not present in query will not make problems.
|
not present in query will not make problems.
|
||||||
|
|
||||||
@ -4544,8 +4541,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
last_name_resolution_table,
|
last_name_resolution_table,
|
||||||
reference,
|
reference,
|
||||||
IGNORE_EXCEPT_NON_UNIQUE,
|
IGNORE_EXCEPT_NON_UNIQUE,
|
||||||
outer_context->check_privileges,
|
TRUE, TRUE);
|
||||||
TRUE);
|
|
||||||
if (! from_field)
|
if (! from_field)
|
||||||
goto error;
|
goto error;
|
||||||
if (from_field == view_ref_found)
|
if (from_field == view_ref_found)
|
||||||
@ -5157,7 +5153,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
|
|||||||
set field_idx properly.
|
set field_idx properly.
|
||||||
*/
|
*/
|
||||||
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
|
(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;
|
thd->set_query_id= save_set_query_id;
|
||||||
triggers= table->triggers;
|
triggers= table->triggers;
|
||||||
}
|
}
|
||||||
|
@ -294,15 +294,15 @@ struct Name_resolution_context: Sql_alloc
|
|||||||
bool resolve_in_select_list;
|
bool resolve_in_select_list;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When FALSE we do not check columns right of resolving items, used to
|
Security context of this name resolution context. It's used for views
|
||||||
prevent rights check on underlying tables of view
|
and is non-zero only if the view is defined with SQL SECURITY DEFINER.
|
||||||
*/
|
*/
|
||||||
bool check_privileges;
|
Security_context *security_ctx;
|
||||||
|
|
||||||
Name_resolution_context()
|
Name_resolution_context()
|
||||||
:outer_context(0), table_list(0), select_lex(0),
|
:outer_context(0), table_list(0), select_lex(0),
|
||||||
error_processor_data(0),
|
error_processor_data(0),
|
||||||
check_privileges(TRUE)
|
security_ctx(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
|
@ -4732,6 +4732,7 @@ Item_func_sp::execute(Field **flp)
|
|||||||
if (execute(&it))
|
if (execute(&it))
|
||||||
{
|
{
|
||||||
null_value= 1;
|
null_value= 1;
|
||||||
|
context->process_error(current_thd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!(f= *flp))
|
if (!(f= *flp))
|
||||||
@ -4754,9 +4755,17 @@ Item_func_sp::execute(Item **itp)
|
|||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
int res= -1;
|
int res= -1;
|
||||||
Sub_statement_state statement_state;
|
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;
|
goto error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4774,9 +4783,14 @@ Item_func_sp::execute(Item **itp)
|
|||||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
ER_FAILED_ROUTINE_BREAK_BINLOG,
|
ER_FAILED_ROUTINE_BREAK_BINLOG,
|
||||||
ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
|
ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
sp_restore_security_context(thd, save_ctx);
|
sp_restore_security_context(thd, save_ctx_func);
|
||||||
error:
|
error:
|
||||||
|
if (save_security_ctx)
|
||||||
|
thd->security_ctx= save_security_ctx;
|
||||||
|
#else
|
||||||
|
error:
|
||||||
|
#endif
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4957,8 +4971,20 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
|
|||||||
bool res;
|
bool res;
|
||||||
DBUG_ASSERT(fixed == 0);
|
DBUG_ASSERT(fixed == 0);
|
||||||
res= Item_func::fix_fields(thd, ref);
|
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;
|
Security_context *save_ctx;
|
||||||
if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx)))
|
if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx)))
|
||||||
sp_restore_security_context(thd, 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);
|
select_result *result);
|
||||||
bool mysql_union(THD *thd, LEX *lex, select_result *result,
|
bool mysql_union(THD *thd, LEX *lex, select_result *result,
|
||||||
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
|
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
|
||||||
int mysql_handle_derived(LEX *lex, int (*processor)(THD *thd,
|
bool mysql_handle_derived(LEX *lex, bool (*processor)(THD *thd,
|
||||||
LEX *lex,
|
LEX *lex,
|
||||||
TABLE_LIST *table));
|
TABLE_LIST *table));
|
||||||
int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
|
bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
|
||||||
int mysql_derived_filling(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,
|
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
||||||
Item ***copy_func, Field **from_field,
|
Item ***copy_func, Field **from_field,
|
||||||
bool group, bool modify_item,
|
bool group, bool modify_item,
|
||||||
@ -793,7 +793,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||||||
Field *
|
Field *
|
||||||
find_field_in_table(THD *thd, TABLE *table, const char *name,
|
find_field_in_table(THD *thd, TABLE *table, const char *name,
|
||||||
uint length, bool check_grants, bool allow_rowid,
|
uint length, bool check_grants, bool allow_rowid,
|
||||||
uint *cached_field_index_ptr);
|
uint *cached_field_index_ptr,
|
||||||
|
Security_context *sctx);
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
#include <openssl/des.h>
|
#include <openssl/des.h>
|
||||||
struct st_des_keyblock
|
struct st_des_keyblock
|
||||||
|
@ -5210,8 +5210,7 @@ ER_WARN_VIEW_WITHOUT_KEY
|
|||||||
rus "Обновляемый view не содержит ключа использованных(ой) в нем таблиц(ы)"
|
rus "Обновляемый view не содержит ключа использованных(ой) в нем таблиц(ы)"
|
||||||
ukr "View, що оновлюеться, не м╕стить повного ключа таблиц╕(ь), що викор╕стана в ньюому"
|
ukr "View, що оновлюеться, не м╕стить повного ключа таблиц╕(ь), що викор╕стана в ньюому"
|
||||||
ER_VIEW_INVALID
|
ER_VIEW_INVALID
|
||||||
eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s)"
|
eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them"
|
||||||
rus "View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÔÏÌÂÃÙ ÉÌÉ ÆÕÎËÃÉÉ"
|
|
||||||
ER_SP_NO_DROP_SP
|
ER_SP_NO_DROP_SP
|
||||||
eng "Can't drop or alter a %s from within another stored routine"
|
eng "Can't drop or alter a %s from within another stored routine"
|
||||||
ER_SP_GOTO_IN_HNDLR
|
ER_SP_GOTO_IN_HNDLR
|
||||||
|
@ -934,6 +934,9 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
|
|||||||
ACL_USER *acl_user= 0;
|
ACL_USER *acl_user= 0;
|
||||||
DBUG_ENTER("acl_getroot_no_password");
|
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->user= user;
|
||||||
sctx->host= host;
|
sctx->host= host;
|
||||||
sctx->ip= ip;
|
sctx->ip= ip;
|
||||||
@ -3512,17 +3515,32 @@ end:
|
|||||||
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
||||||
uint show_table, uint number, bool no_errors)
|
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;
|
Security_context *sctx= thd->security_ctx;
|
||||||
|
uint i;
|
||||||
DBUG_ENTER("check_grant");
|
DBUG_ENTER("check_grant");
|
||||||
DBUG_ASSERT(number > 0);
|
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;
|
want_access&= ~sctx->master_access;
|
||||||
if (!want_access)
|
if (!want_access)
|
||||||
DBUG_RETURN(0); // ok
|
DBUG_RETURN(0); // ok
|
||||||
|
|
||||||
rw_rdlock(&LOCK_grant);
|
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;
|
GRANT_TABLE *grant_table;
|
||||||
if (!(~table->grant.privilege & want_access) ||
|
if (!(~table->grant.privilege & want_access) ||
|
||||||
@ -3532,8 +3550,16 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
|||||||
It is subquery in the FROM clause. VIEW set table->derived after
|
It is subquery in the FROM clause. VIEW set table->derived after
|
||||||
table opening, but this function always called before table opening.
|
table opening, but this function always called before table opening.
|
||||||
*/
|
*/
|
||||||
table->grant.want_privilege= 0;
|
if (!table->referencing_view)
|
||||||
continue; // Already checked
|
{
|
||||||
|
/*
|
||||||
|
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,
|
if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
|
||||||
table->db, sctx->priv_user,
|
table->db, sctx->priv_user,
|
||||||
@ -5842,24 +5868,37 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
|||||||
const char *db, const char *table)
|
const char *db, const char *table)
|
||||||
{
|
{
|
||||||
Security_context *sctx= thd->security_ctx;
|
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 */
|
/* --skip-grants */
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
{
|
{
|
||||||
|
DBUG_PRINT("info", ("skip grants"));
|
||||||
grant->privilege= ~NO_ACCESS; // everything is allowed
|
grant->privilege= ~NO_ACCESS; // everything is allowed
|
||||||
return;
|
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* global privileges */
|
/* global privileges */
|
||||||
grant->privilege= sctx->master_access;
|
grant->privilege= sctx->master_access;
|
||||||
|
|
||||||
if (!sctx->priv_user)
|
if (!sctx->priv_user)
|
||||||
return; // it is slave
|
{
|
||||||
|
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||||
|
DBUG_VOID_RETURN; // it is slave
|
||||||
|
}
|
||||||
|
|
||||||
/* db privileges */
|
/* db privileges */
|
||||||
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
|
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
|
||||||
|
|
||||||
if (!grant_option)
|
if (!grant_option)
|
||||||
return;
|
{
|
||||||
|
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
/* table privileges */
|
/* table privileges */
|
||||||
if (grant->version != grant_version)
|
if (grant->version != grant_version)
|
||||||
@ -5876,6 +5915,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
|||||||
{
|
{
|
||||||
grant->privilege|= grant->grant_table->privs;
|
grant->privilege|= grant->grant_table->privs;
|
||||||
}
|
}
|
||||||
|
DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* NO_EMBEDDED_ACCESS_CHECKS */
|
#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"
|
derived/information schema tables and views possible. Thus "counter"
|
||||||
may be still zero for prelocked statement...
|
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.
|
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)
|
thd->lex->sroutines_list.elements)
|
||||||
{
|
{
|
||||||
bool first_no_prelocking, need_prelocking;
|
bool first_no_prelocking, need_prelocking;
|
||||||
@ -2025,7 +2025,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||||||
/* VIEW placeholder */
|
/* VIEW placeholder */
|
||||||
(*counter)--;
|
(*counter)--;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
tables->next_global list consists of two parts:
|
tables->next_global list consists of two parts:
|
||||||
1) Query tables and underlying tables of views.
|
1) Query tables and underlying tables of views.
|
||||||
2) Tables used by all stored routines that this statement invokes on
|
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.
|
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);
|
DBUG_RETURN(((Item_field*) (field_it.item()))->field);
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (check_grants &&
|
if (check_grant_column_in_sctx(thd, &table_list->grant,
|
||||||
check_grant_column(thd, &table_list->grant,
|
table_list->view_db.str,
|
||||||
table_list->view_db.str,
|
table_list->view_name.str, name, length,
|
||||||
table_list->view_name.str,
|
check_grants,
|
||||||
name, length))
|
table_list->security_ctx))
|
||||||
DBUG_RETURN(WRONG_GRANT);
|
DBUG_RETURN(WRONG_GRANT);
|
||||||
#endif
|
#endif
|
||||||
// in PS use own arena or data will be freed after prepare
|
// 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 *
|
Field *
|
||||||
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
|
||||||
bool check_grants, bool allow_rowid,
|
bool check_grants, bool allow_rowid,
|
||||||
uint *cached_field_index_ptr)
|
uint *cached_field_index_ptr,
|
||||||
|
Security_context *sctx)
|
||||||
{
|
{
|
||||||
Field **field_ptr, *field;
|
Field **field_ptr, *field;
|
||||||
uint cached_field_index= *cached_field_index_ptr;
|
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 */
|
/* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
|
||||||
if (cached_field_index < table->s->fields &&
|
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))
|
table->field[cached_field_index]->field_name, name))
|
||||||
field_ptr= table->field + cached_field_index;
|
field_ptr= table->field + cached_field_index;
|
||||||
else if (table->s->name_hash.records)
|
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);
|
update_field_dependencies(thd, field, table);
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (check_grants && check_grant_column(thd, &table->grant,
|
if (check_grant_column_in_sctx(thd, &table->grant,
|
||||||
table->s->db,
|
table->s->db, table->s->table_name,
|
||||||
table->s->table_name, name, length))
|
name, length,
|
||||||
|
check_grants, sctx))
|
||||||
field= WRONG_GRANT;
|
field= WRONG_GRANT;
|
||||||
#endif
|
#endif
|
||||||
DBUG_RETURN(field);
|
DBUG_RETURN(field);
|
||||||
@ -3054,7 +3099,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
|
|||||||
DBUG_ASSERT(table_list->table);
|
DBUG_ASSERT(table_list->table);
|
||||||
if ((fld= find_field_in_table(thd, table_list->table, name, length,
|
if ((fld= find_field_in_table(thd, table_list->table, name, length,
|
||||||
check_grants_table, allow_rowid,
|
check_grants_table, allow_rowid,
|
||||||
cached_field_index_ptr)))
|
cached_field_index_ptr,
|
||||||
|
table_list->security_ctx)))
|
||||||
*actual_table= table_list;
|
*actual_table= table_list;
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
/* check for views with temporary table algorithm */
|
/* check for views with temporary table algorithm */
|
||||||
@ -3188,7 +3234,8 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||||||
test(table_ref->table->
|
test(table_ref->table->
|
||||||
grant.want_privilege) &&
|
grant.want_privilege) &&
|
||||||
check_privileges,
|
check_privileges,
|
||||||
1, &(item->cached_field_index));
|
1, &(item->cached_field_index),
|
||||||
|
table_ref->security_ctx);
|
||||||
else
|
else
|
||||||
found= find_field_in_table_ref(thd, table_ref, name, item->name,
|
found= find_field_in_table_ref(thd, table_ref, name, item->name,
|
||||||
NULL, NULL, length, ref,
|
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)
|
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||||
{
|
{
|
||||||
if (table->view && table->effective_algorithm == VIEW_ALGORITHM_MERGE)
|
if (table->merge_underlying_list)
|
||||||
list= make_leaves_list(list, table->ancestor);
|
{
|
||||||
|
DBUG_ASSERT(table->view &&
|
||||||
|
table->effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||||
|
list= make_leaves_list(list, table->merge_underlying_list);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*list= table;
|
*list= table;
|
||||||
@ -4425,16 +4476,17 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
|
|||||||
table_list;
|
table_list;
|
||||||
table_list= table_list->next_local)
|
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;
|
Query_arena *arena= thd->stmt_arena, backup;
|
||||||
bool res;
|
bool res;
|
||||||
if (arena->is_conventional())
|
if (arena->is_conventional())
|
||||||
arena= 0; // For easier test
|
arena= 0; // For easier test
|
||||||
else
|
else
|
||||||
thd->set_n_backup_active_arena(arena, &backup);
|
thd->set_n_backup_active_arena(arena, &backup);
|
||||||
res= table_list->setup_ancestor(thd);
|
res= table_list->setup_underlying(thd);
|
||||||
if (arena)
|
if (arena)
|
||||||
thd->restore_active_arena(arena, &backup);
|
thd->restore_active_arena(arena, &backup);
|
||||||
if (res)
|
if (res)
|
||||||
|
@ -2208,15 +2208,10 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
|
|||||||
tables_used->view_db.length + 1,
|
tables_used->view_db.length + 1,
|
||||||
HA_CACHE_TBL_NONTRANSACT, 0, 0))
|
HA_CACHE_TBL_NONTRANSACT, 0, 0))
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
{
|
/*
|
||||||
TABLE_COUNTER_TYPE inc= register_tables_from_list(tables_used->ancestor,
|
We do not need to register view tables here because they are already
|
||||||
n + 1,
|
present in the global list.
|
||||||
block_table + 1);
|
*/
|
||||||
if (!inc)
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
n+= inc;
|
|
||||||
block_table+= inc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2832,13 +2827,6 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
|
|||||||
tables_used->view_name.str,
|
tables_used->view_name.str,
|
||||||
tables_used->view_db.str));
|
tables_used->view_db.str));
|
||||||
*tables_type|= HA_CACHE_TBL_NONTRANSACT;
|
*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
|
else
|
||||||
{
|
{
|
||||||
|
@ -416,8 +416,9 @@ bool mysql_multi_delete_prepare(THD *thd)
|
|||||||
if (!(target_tbl->table= target_tbl->correspondent_table->table))
|
if (!(target_tbl->table= target_tbl->correspondent_table->table))
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(target_tbl->correspondent_table->view &&
|
DBUG_ASSERT(target_tbl->correspondent_table->view &&
|
||||||
target_tbl->correspondent_table->ancestor &&
|
target_tbl->correspondent_table->merge_underlying_list &&
|
||||||
target_tbl->correspondent_table->ancestor->next_local);
|
target_tbl->correspondent_table->merge_underlying_list->
|
||||||
|
next_local);
|
||||||
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
|
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
|
||||||
target_tbl->correspondent_table->view_db.str,
|
target_tbl->correspondent_table->view_db.str,
|
||||||
target_tbl->correspondent_table->view_name.str);
|
target_tbl->correspondent_table->view_name.str);
|
||||||
|
@ -35,14 +35,14 @@
|
|||||||
processor procedure of derived table processing
|
processor procedure of derived table processing
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
0 ok
|
FALSE OK
|
||||||
1 Error and error message given
|
TRUE Error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
bool
|
||||||
mysql_handle_derived(LEX *lex, int (*processor)(THD*, LEX*, TABLE_LIST*))
|
mysql_handle_derived(LEX *lex, bool (*processor)(THD*, LEX*, TABLE_LIST*))
|
||||||
{
|
{
|
||||||
int res= 0;
|
bool res= FALSE;
|
||||||
if (lex->derived_tables)
|
if (lex->derived_tables)
|
||||||
{
|
{
|
||||||
lex->thd->derived_tables_processing= TRUE;
|
lex->thd->derived_tables_processing= TRUE;
|
||||||
@ -95,16 +95,16 @@ out:
|
|||||||
close_thread_tables()
|
close_thread_tables()
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
0 ok
|
FALSE OK
|
||||||
1 Error and an error message was given
|
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;
|
SELECT_LEX_UNIT *unit= orig_table_list->derived;
|
||||||
int res= 0;
|
|
||||||
ulonglong create_options;
|
ulonglong create_options;
|
||||||
DBUG_ENTER("mysql_derived_prepare");
|
DBUG_ENTER("mysql_derived_prepare");
|
||||||
|
bool res= FALSE;
|
||||||
if (unit)
|
if (unit)
|
||||||
{
|
{
|
||||||
SELECT_LEX *first_select= unit->first_select();
|
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;
|
sl->context.outer_context= 0;
|
||||||
|
|
||||||
if (!(derived_result= new select_union))
|
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
|
// st_select_lex_unit::prepare correctly work for single select
|
||||||
if ((res= unit->prepare(thd, derived_result, 0)))
|
if ((res= unit->prepare(thd, derived_result, 0)))
|
||||||
@ -184,7 +184,10 @@ exit:
|
|||||||
table->derived_select_number= first_select->select_number;
|
table->derived_select_number= first_select->select_number;
|
||||||
table->s->tmp_table= TMP_TABLE;
|
table->s->tmp_table= TMP_TABLE;
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#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
|
#endif
|
||||||
orig_table_list->db= (char *)"";
|
orig_table_list->db= (char *)"";
|
||||||
orig_table_list->db_length= 0;
|
orig_table_list->db_length= 0;
|
||||||
@ -195,8 +198,8 @@ exit:
|
|||||||
thd->derived_tables= table;
|
thd->derived_tables= table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (orig_table_list->ancestor)
|
else if (orig_table_list->merge_underlying_list)
|
||||||
orig_table_list->set_ancestor();
|
orig_table_list->set_underlying_merge();
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,15 +223,15 @@ exit:
|
|||||||
Due to evaluation of LIMIT clause it can not be used at prepared stage.
|
Due to evaluation of LIMIT clause it can not be used at prepared stage.
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
0 ok
|
FALSE OK
|
||||||
1 Error and an error message was given
|
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;
|
TABLE *table= orig_table_list->table;
|
||||||
SELECT_LEX_UNIT *unit= orig_table_list->derived;
|
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 */
|
/*check that table creation pass without problem and it is derived table */
|
||||||
if (table && unit)
|
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
|
there were no derived tables
|
||||||
*/
|
*/
|
||||||
if (derived_result->flush())
|
if (derived_result->flush())
|
||||||
res= 1;
|
res= TRUE;
|
||||||
|
|
||||||
if (!lex->describe)
|
if (!lex->describe)
|
||||||
unit->cleanup();
|
unit->cleanup();
|
||||||
|
@ -801,6 +801,11 @@ typedef struct st_lex
|
|||||||
*/
|
*/
|
||||||
uint table_count;
|
uint table_count;
|
||||||
uint8 describe;
|
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 derived_tables;
|
||||||
uint8 create_view_algorithm;
|
uint8 create_view_algorithm;
|
||||||
uint8 create_view_check;
|
uint8 create_view_check;
|
||||||
|
@ -5026,8 +5026,13 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
|
|||||||
{
|
{
|
||||||
uint found=0;
|
uint found=0;
|
||||||
ulong found_access=0;
|
ulong found_access=0;
|
||||||
TABLE_LIST *org_tables=tables;
|
TABLE_LIST *org_tables= tables;
|
||||||
for (; tables; tables= tables->next_global)
|
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 &&
|
if (tables->schema_table &&
|
||||||
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
|
(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);
|
information_schema_name.str);
|
||||||
return TRUE;
|
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 ||
|
if (tables->derived || tables->schema_table || tables->belong_to_view ||
|
||||||
(tables->table && (int)tables->table->s->tmp_table) ||
|
(tables->table && (int)tables->table->s->tmp_table) ||
|
||||||
my_tz_check_n_skip_implicit_tables(&tables,
|
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
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
table_list->grant.want_privilege= want_privilege;
|
table_list->grant.want_privilege= want_privilege;
|
||||||
table_list->table->grant.want_privilege= want_privilege;
|
table_list->table->grant.want_privilege= want_privilege;
|
||||||
|
table_list->register_want_access(want_privilege);
|
||||||
#endif
|
#endif
|
||||||
thd->lex->select_lex.no_wrap_view_item= TRUE;
|
thd->lex->select_lex.no_wrap_view_item= TRUE;
|
||||||
res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
|
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->grant.want_privilege=
|
||||||
table_list->table->grant.want_privilege=
|
table_list->table->grant.want_privilege=
|
||||||
(SELECT_ACL & ~table_list->table->grant.privilege);
|
(SELECT_ACL & ~table_list->table->grant.privilege);
|
||||||
|
table_list->register_want_access(SELECT_ACL);
|
||||||
#endif
|
#endif
|
||||||
if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
|
if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -195,6 +195,7 @@ int mysql_update(THD *thd,
|
|||||||
/* Check the fields we are going to modify */
|
/* Check the fields we are going to modify */
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
|
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
|
||||||
|
table_list->register_want_access(want_privilege);
|
||||||
#endif
|
#endif
|
||||||
if (setup_fields_with_no_wrap(thd, 0, fields, 1, 0, 0))
|
if (setup_fields_with_no_wrap(thd, 0, fields, 1, 0, 0))
|
||||||
DBUG_RETURN(1); /* purecov: inspected */
|
DBUG_RETURN(1); /* purecov: inspected */
|
||||||
@ -584,6 +585,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
|||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
table_list->grant.want_privilege= table->grant.want_privilege=
|
table_list->grant.want_privilege= table->grant.want_privilege=
|
||||||
(SELECT_ACL & ~table->grant.privilege);
|
(SELECT_ACL & ~table->grant.privilege);
|
||||||
|
table_list->register_want_access(SELECT_ACL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
|
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
|
||||||
|
115
sql/sql_view.cc
115
sql/sql_view.cc
@ -722,6 +722,7 @@ loop_out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
read VIEW .frm and create structures
|
read VIEW .frm and create structures
|
||||||
|
|
||||||
@ -738,11 +739,26 @@ loop_out:
|
|||||||
my_bool
|
my_bool
|
||||||
mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||||
{
|
{
|
||||||
|
THD *thd= current_thd;
|
||||||
DBUG_ENTER("mysql_make_view");
|
DBUG_ENTER("mysql_make_view");
|
||||||
DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name));
|
DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name));
|
||||||
|
|
||||||
if (table->view)
|
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",
|
DBUG_PRINT("info",
|
||||||
("VIEW %s.%s is already processed on previous PS/SP execution",
|
("VIEW %s.%s is already processed on previous PS/SP execution",
|
||||||
table->view_db.str, table->view_name.str));
|
table->view_db.str, table->view_name.str));
|
||||||
@ -750,7 +766,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SELECT_LEX *end;
|
SELECT_LEX *end;
|
||||||
THD *thd= current_thd;
|
|
||||||
LEX *old_lex= thd->lex, *lex;
|
LEX *old_lex= thd->lex, *lex;
|
||||||
SELECT_LEX *view_select;
|
SELECT_LEX *view_select;
|
||||||
int res= 0;
|
int res= 0;
|
||||||
@ -769,7 +784,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
if (!table->timestamp.str)
|
if (!table->timestamp.str)
|
||||||
table->timestamp.str= table->timestamp_buffer;
|
table->timestamp.str= table->timestamp_buffer;
|
||||||
/* prepare default values for old format */
|
/* 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.str= table->definer.host.str= 0;
|
||||||
table->definer.user.length= table->definer.host.length= 0;
|
table->definer.user.length= table->definer.host.length= 0;
|
||||||
|
|
||||||
@ -880,6 +895,10 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
goto err;
|
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
|
mark to avoid temporary table using and put view reference and find
|
||||||
last view table
|
last view table
|
||||||
@ -890,6 +909,22 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
{
|
{
|
||||||
tbl->skip_temporary= 1;
|
tbl->skip_temporary= 1;
|
||||||
tbl->belong_to_view= top_view;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -914,16 +949,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
table->next_global= view_tables;
|
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
|
If we are opening this view as part of implicit LOCK TABLES, then
|
||||||
this view serves as simple placeholder and we should not continue
|
this view serves as simple placeholder and we should not continue
|
||||||
@ -932,7 +957,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
if (table->prelocking_placeholder)
|
if (table->prelocking_placeholder)
|
||||||
goto ok2;
|
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 */
|
/* move SQL_NO_CACHE & Co to whole query */
|
||||||
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
|
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
|
||||||
@ -941,6 +966,37 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
if (view_select->options & OPTION_TO_QUERY_CACHE)
|
if (view_select->options & OPTION_TO_QUERY_CACHE)
|
||||||
old_lex->select_lex.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
|
check MERGE algorithm ability
|
||||||
- algorithm is not explicit TEMPORARY TABLE
|
- algorithm is not explicit TEMPORARY TABLE
|
||||||
@ -962,24 +1018,28 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
|||||||
table->updatable= (table->updatable_view != 0);
|
table->updatable= (table->updatable_view != 0);
|
||||||
table->effective_with_check=
|
table->effective_with_check=
|
||||||
old_lex->get_effective_with_check(table);
|
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 */
|
/* prepare view context */
|
||||||
lex->select_lex.context.resolve_in_table_list_only(table->ancestor=
|
lex->select_lex.context.resolve_in_table_list_only(view_tables);
|
||||||
view_tables);
|
|
||||||
lex->select_lex.context.outer_context= 0;
|
lex->select_lex.context.outer_context= 0;
|
||||||
lex->select_lex.context.select_lex= table->select_lex;
|
lex->select_lex.context.select_lex= table->select_lex;
|
||||||
lex->select_lex.select_n_having_items+=
|
lex->select_lex.select_n_having_items+=
|
||||||
table->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
|
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
|
to the same select as original view (again we can use LEX::select_lex
|
||||||
@ -1012,7 +1072,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;
|
table->where= view_select->where;
|
||||||
/*
|
/*
|
||||||
Add subqueries units to SELECT into which we merging current view.
|
Add subqueries units to SELECT into which we merging current view.
|
||||||
@ -1078,6 +1138,11 @@ ok2:
|
|||||||
if (!old_lex->time_zone_tables_used && thd->lex->time_zone_tables_used)
|
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;
|
old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used;
|
||||||
thd->lex= old_lex;
|
thd->lex= old_lex;
|
||||||
|
if (!table->prelocking_placeholder && table->prepare_security(thd))
|
||||||
|
{
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
err:
|
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
|
DESCRIPTION
|
||||||
Replace all views that only uses one table with the table itself.
|
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
|
This allows us to treat the view as a simple table and even update
|
||||||
it
|
it (it is a kind of optimisation)
|
||||||
|
|
||||||
SYNOPSIS
|
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;
|
TABLE_LIST *tbl;
|
||||||
|
|
||||||
if ((tbl= ancestor))
|
if ((tbl= merge_underlying_list))
|
||||||
{
|
{
|
||||||
/* This is a view. Process all tables of view */
|
/* This is a view. Process all tables of view */
|
||||||
DBUG_ASSERT(view);
|
DBUG_ASSERT(view && effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||||
do
|
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
|
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)
|
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));
|
} while ((tbl= tbl->next_local));
|
||||||
|
|
||||||
if (!multitable_view)
|
if (!multitable_view)
|
||||||
{
|
{
|
||||||
table= ancestor->table;
|
table= merge_underlying_list->table;
|
||||||
schema_table= ancestor->schema_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
|
setup fields of placeholder of merged VIEW
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
st_table_list::setup_ancestor()
|
st_table_list::setup_underlying()
|
||||||
thd - thread handler
|
thd - thread handler
|
||||||
|
|
||||||
NOTES
|
|
||||||
ancestor is list of tables and views used by view (underlying tables/views)
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
It is:
|
It is:
|
||||||
- preparing translation table for view columns
|
- preparing translation table for view columns
|
||||||
@ -1858,10 +1857,11 @@ void st_table_list::set_ancestor()
|
|||||||
TRUE - error
|
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");
|
DBUG_ENTER("st_table_list::setup_underlying");
|
||||||
if (!field_translation)
|
|
||||||
|
if (!field_translation && merge_underlying_list)
|
||||||
{
|
{
|
||||||
Field_translator *transl;
|
Field_translator *transl;
|
||||||
SELECT_LEX *select= &view->select_lex;
|
SELECT_LEX *select= &view->select_lex;
|
||||||
@ -1875,10 +1875,10 @@ bool st_table_list::setup_ancestor(THD *thd)
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (tbl= ancestor; tbl; tbl= tbl->next_local)
|
for (tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||||
{
|
{
|
||||||
if (tbl->ancestor &&
|
if (tbl->merge_underlying_list &&
|
||||||
tbl->setup_ancestor(thd))
|
tbl->setup_underlying(thd))
|
||||||
{
|
{
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
@ -1941,7 +1941,7 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("st_table_list::prep_where");
|
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))
|
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");
|
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 */
|
/* see comment of check_opt_type parameter */
|
||||||
if (tbl->view &&
|
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)
|
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)
|
if (tbl->check_option)
|
||||||
item= and_conds(item, 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 */
|
/* Hide "Unknown column" or "Unknown function" error */
|
||||||
if (thd->net.last_errno == ER_BAD_FIELD_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();
|
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)
|
else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
|
||||||
{
|
{
|
||||||
|
TABLE_LIST *top= top_table();
|
||||||
thd->clear_error();
|
thd->clear_error();
|
||||||
// TODO: make correct error message
|
// 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)
|
st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
|
||||||
{
|
{
|
||||||
/* is this real table and table which we are looking for? */
|
/* 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;
|
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;
|
TABLE_LIST *result;
|
||||||
if ((result= tbl->find_underlying_table(table_to_find)))
|
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,
|
bool st_table_list::check_single_table(st_table_list **table, table_map map,
|
||||||
st_table_list *view)
|
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)
|
if (tbl->table)
|
||||||
{
|
{
|
||||||
@ -2243,8 +2248,8 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(view && ancestor);
|
DBUG_ASSERT(view && merge_underlying_list);
|
||||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||||
if (tbl->set_insert_values(mem_root))
|
if (tbl->set_insert_values(mem_root))
|
||||||
return TRUE;
|
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,
|
Natural_join_column::Natural_join_column(Field_translator *field_param,
|
||||||
TABLE_LIST *tab)
|
TABLE_LIST *tab)
|
||||||
{
|
{
|
||||||
@ -2498,6 +2656,9 @@ Natural_join_column::check_grants(THD *thd, const char *name, uint length)
|
|||||||
GRANT_INFO *grant;
|
GRANT_INFO *grant;
|
||||||
const char *db_name;
|
const char *db_name;
|
||||||
const char *table_name;
|
const char *table_name;
|
||||||
|
Security_context *save_security_ctx= 0;
|
||||||
|
Security_context *new_sctx= table_ref->security_ctx;
|
||||||
|
bool res;
|
||||||
|
|
||||||
if (view_field)
|
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;
|
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
|
#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_unit;
|
||||||
class st_select_lex;
|
class st_select_lex;
|
||||||
class COND_EQUAL;
|
class COND_EQUAL;
|
||||||
|
class Security_context;
|
||||||
|
|
||||||
/* Order clause list element */
|
/* Order clause list element */
|
||||||
|
|
||||||
@ -47,6 +48,11 @@ typedef struct st_grant_info
|
|||||||
uint version;
|
uint version;
|
||||||
ulong privilege;
|
ulong privilege;
|
||||||
ulong want_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;
|
} GRANT_INFO;
|
||||||
|
|
||||||
enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2,
|
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
|
#define VIEW_CHECK_SKIP 2
|
||||||
|
|
||||||
struct st_lex;
|
struct st_lex;
|
||||||
struct st_table_list;
|
|
||||||
class select_union;
|
class select_union;
|
||||||
class TMP_TABLE_PARAM;
|
class TMP_TABLE_PARAM;
|
||||||
|
|
||||||
@ -525,10 +530,35 @@ typedef struct st_table_list
|
|||||||
Field_translator *field_translation; /* array of VIEW fields */
|
Field_translator *field_translation; /* array of VIEW fields */
|
||||||
/* pointer to element after last one in translation table above */
|
/* pointer to element after last one in translation table above */
|
||||||
Field_translator *field_translation_end;
|
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 */
|
/* most upper view this table belongs to */
|
||||||
st_table_list *belong_to_view;
|
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
|
List of all base tables local to a subquery including all view
|
||||||
tables. Unlike 'next_local', this in this list views are *not*
|
tables. Unlike 'next_local', this in this list views are *not*
|
||||||
@ -595,9 +625,9 @@ typedef struct st_table_list
|
|||||||
bool prelocking_placeholder;
|
bool prelocking_placeholder;
|
||||||
|
|
||||||
void calc_md5(char *buffer);
|
void calc_md5(char *buffer);
|
||||||
void set_ancestor();
|
void set_underlying_merge();
|
||||||
int view_check_option(THD *thd, bool ignore_failure);
|
int view_check_option(THD *thd, bool ignore_failure);
|
||||||
bool setup_ancestor(THD *thd);
|
bool setup_underlying(THD *thd);
|
||||||
void cleanup_items();
|
void cleanup_items();
|
||||||
bool placeholder() {return derived || view; }
|
bool placeholder() {return derived || view; }
|
||||||
void print(THD *thd, String *str);
|
void print(THD *thd, String *str);
|
||||||
@ -625,6 +655,14 @@ typedef struct st_table_list
|
|||||||
return prep_where(thd, conds, no_where_clause);
|
return prep_where(thd, conds, no_where_clause);
|
||||||
return FALSE;
|
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:
|
private:
|
||||||
bool prep_check_option(THD *thd, uint8 check_opt_type);
|
bool prep_check_option(THD *thd, uint8 check_opt_type);
|
||||||
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
|
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user