summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <anozdrin@mysql.com>2006-03-07 14:28:09 +0300
committerunknown <anozdrin@mysql.com>2006-03-07 14:28:09 +0300
commit99515a3ac8632c942979a24d79bbbec922e03f67 (patch)
treef377d746ddd3a559f6c8a1d2237fbeb30cd08efa
parent07d36fb99a4b9419f60d4c09efc7e6c3fde0051c (diff)
parent3dd927cf1cf4f666d55144862e52e9479fe6c4ff (diff)
downloadmariadb-git-99515a3ac8632c942979a24d79bbbec922e03f67.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/alik/Documents/AllProgs/MySQL/devel/5.0-rt mysql-test/r/sp.result: Auto merged sql/sql_trigger.cc: Auto merged sql/sql_yacc.yy: Auto merged mysql-test/r/skip_grants.result: Merge 5.0 and 5.0-runtime. mysql-test/t/skip_grants.test: Merge 5.0 and 5.0-runtime.
-rw-r--r--client/mysqldump.c48
-rw-r--r--mysql-test/r/gis.result2
-rw-r--r--mysql-test/r/information_schema.result4
-rw-r--r--mysql-test/r/mysqldump.result14
-rw-r--r--mysql-test/r/rpl_ddl.result4
-rw-r--r--mysql-test/r/rpl_sp.result30
-rw-r--r--mysql-test/r/rpl_trigger.result43
-rw-r--r--mysql-test/r/skip_grants.result21
-rw-r--r--mysql-test/r/sp-security.result96
-rw-r--r--mysql-test/r/sp.result28
-rw-r--r--mysql-test/r/sql_mode.result8
-rw-r--r--mysql-test/std_data/bug16266.000001bin0 -> 532 bytes
-rw-r--r--mysql-test/t/rpl_trigger.test74
-rw-r--r--mysql-test/t/skip_grants.test53
-rw-r--r--mysql-test/t/sp-security.test196
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sp.cc55
-rw-r--r--sql/sp_head.cc43
-rw-r--r--sql/sp_head.h1
-rw-r--r--sql/sql_lex.h14
-rw-r--r--sql/sql_parse.cc132
-rw-r--r--sql/sql_trigger.cc110
-rw-r--r--sql/sql_view.cc23
-rw-r--r--sql/sql_yacc.yy244
24 files changed, 987 insertions, 259 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 161197821d6..e0469e00031 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -80,6 +80,7 @@ static char *add_load_option(char *ptr, const char *object,
const char *statement);
static ulong find_set(TYPELIB *lib, const char *x, uint length,
char **err_pos, uint *err_len);
+static char *alloc_query_str(ulong size);
static char *field_escape(char *to,const char *from,uint length);
static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1,
@@ -1304,19 +1305,64 @@ static uint dump_routines_for_db(char *db)
routine_name, row[2], strlen(row[2])));
if (strlen(row[2]))
{
+ char *query_str= NULL;
+ char *definer_begin;
+
if (opt_drop)
fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;;\n",
routine_type[i], routine_name);
+
+ /*
+ Cover DEFINER-clause in version-specific comments.
+
+ TODO: this is definitely a BAD IDEA to parse SHOW CREATE output.
+ We should user INFORMATION_SCHEMA instead. The only problem is
+ that now INFORMATION_SCHEMA does not provide information about
+ routine parameters.
+ */
+
+ definer_begin= strstr(row[2], " DEFINER");
+
+ if (definer_begin)
+ {
+ char *definer_end= strstr(definer_begin, " PROCEDURE");
+
+ if (!definer_end)
+ definer_end= strstr(definer_begin, " FUNCTION");
+
+ if (definer_end)
+ {
+ char *query_str_tail;
+
+ /*
+ Allocate memory for new query string: original string
+ from SHOW statement and version-specific comments.
+ */
+ query_str= alloc_query_str(strlen(row[2]) + 23);
+
+ query_str_tail= strnmov(query_str, row[2],
+ definer_begin - row[2]);
+ query_str_tail= strmov(query_str_tail, "*/ /*!50019");
+ query_str_tail= strnmov(query_str_tail, definer_begin,
+ definer_end - definer_begin);
+ query_str_tail= strxmov(query_str_tail, "*/ /*!50003",
+ definer_end, NullS);
+ }
+ }
+
/*
we need to change sql_mode only for the CREATE
PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name
*/;
fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/;;\n",
row[1] /* sql_mode */);
- fprintf(sql_file, "/*!50003 %s */;;\n", row[2]);
+ fprintf(sql_file, "/*!50003 %s */;;\n",
+ (query_str != NULL ? query_str : row[2]));
fprintf(sql_file,
"/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/"
";;\n");
+
+ my_free(query_str, MYF(MY_ALLOW_ZERO_PTR));
}
} /* end of routine printing */
} /* end of list of routines */
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result
index 049ba784dc9..13e2d56d83e 100644
--- a/mysql-test/r/gis.result
+++ b/mysql-test/r/gis.result
@@ -680,7 +680,7 @@ drop procedure if exists fn3;
create function fn3 () returns point return GeomFromText("point(1 1)");
show create function fn3;
Function sql_mode Create Function
-fn3 CREATE FUNCTION `fn3`() RETURNS point
+fn3 CREATE DEFINER=`root`@`localhost` FUNCTION `fn3`() RETURNS point
return GeomFromText("point(1 1)")
select astext(fn3());
astext(fn3())
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index d3576e24a44..1c845c73e4b 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -309,7 +309,7 @@ Function sql_mode Create Function
sub1
show create function sub2;
Function sql_mode Create Function
-sub2 CREATE FUNCTION `sub2`(i int) RETURNS int(11)
+sub2 CREATE DEFINER=`mysqltest_1`@`localhost` FUNCTION `sub2`(i int) RETURNS int(11)
return i+1
show function status like "sub2";
Db Name Type Definer Modified Created Security_type Comment
@@ -317,7 +317,7 @@ test sub2 FUNCTION mysqltest_1@localhost # # DEFINER
drop function sub2;
show create procedure sel2;
Procedure sql_mode Create Procedure
-sel2 CREATE PROCEDURE `sel2`()
+sel2 CREATE DEFINER=`root`@`localhost` PROCEDURE `sel2`()
begin
select * from t1;
select * from t2;
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index d156e711167..e6ac9fbc740 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -2210,12 +2210,12 @@ UNLOCK TABLES;
DELIMITER ;;
/*!50003 DROP FUNCTION IF EXISTS `bug9056_func1` */;;
/*!50003 SET SESSION SQL_MODE=""*/;;
-/*!50003 CREATE FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11)
+/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 FUNCTION `bug9056_func1`(a INT, b INT) RETURNS int(11)
RETURN a+b */;;
/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;;
/*!50003 DROP FUNCTION IF EXISTS `bug9056_func2` */;;
/*!50003 SET SESSION SQL_MODE=""*/;;
-/*!50003 CREATE FUNCTION `bug9056_func2`(f1 char binary) RETURNS char(1)
+/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 FUNCTION `bug9056_func2`(f1 char binary) RETURNS char(1)
begin
set f1= concat( 'hello', f1 );
return f1;
@@ -2223,17 +2223,17 @@ end */;;
/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;;
/*!50003 DROP PROCEDURE IF EXISTS `a'b` */;;
/*!50003 SET SESSION SQL_MODE="REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI"*/;;
-/*!50003 CREATE PROCEDURE "a'b"()
+/*!50003 CREATE*/ /*!50019 DEFINER="root"@"localhost"*/ /*!50003 PROCEDURE "a'b"()
select 1 */;;
/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;;
/*!50003 DROP PROCEDURE IF EXISTS `bug9056_proc1` */;;
/*!50003 SET SESSION SQL_MODE=""*/;;
-/*!50003 CREATE PROCEDURE `bug9056_proc1`(IN a INT, IN b INT, OUT c INT)
+/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 PROCEDURE `bug9056_proc1`(IN a INT, IN b INT, OUT c INT)
BEGIN SELECT a+b INTO c; end */;;
/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;;
/*!50003 DROP PROCEDURE IF EXISTS `bug9056_proc2` */;;
/*!50003 SET SESSION SQL_MODE=""*/;;
-/*!50003 CREATE PROCEDURE `bug9056_proc2`(OUT a INT)
+/*!50003 CREATE*/ /*!50019 DEFINER=`root`@`localhost`*/ /*!50003 PROCEDURE `bug9056_proc2`(OUT a INT)
BEGIN
select sum(id) from t1 into a;
END */;;
@@ -2685,11 +2685,11 @@ return 42 */|
select 42 */|
show create function f;
Function sql_mode Create Function
-f CREATE FUNCTION `f`() RETURNS bigint(20)
+f CREATE DEFINER=`root`@`localhost` FUNCTION `f`() RETURNS bigint(20)
return 42
show create procedure p;
Procedure sql_mode Create Procedure
-p CREATE PROCEDURE `p`()
+p CREATE DEFINER=`root`@`localhost` PROCEDURE `p`()
select 42
drop function f;
drop procedure p;
diff --git a/mysql-test/r/rpl_ddl.result b/mysql-test/r/rpl_ddl.result
index c56c9f20cf8..92e91b31459 100644
--- a/mysql-test/r/rpl_ddl.result
+++ b/mysql-test/r/rpl_ddl.result
@@ -1133,7 +1133,7 @@ SHOW PROCEDURE STATUS LIKE 'p1';
Db mysqltest1
Name p1
Type PROCEDURE
-Definer @
+Definer root@localhost
Modified #
Created #
Security_type DEFINER
@@ -1199,7 +1199,7 @@ SHOW PROCEDURE STATUS LIKE 'p1';
Db mysqltest1
Name p1
Type PROCEDURE
-Definer @
+Definer root@localhost
Modified #
Created #
Security_type DEFINER
diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result
index a42c33ce333..5dfda16c763 100644
--- a/mysql-test/r/rpl_sp.result
+++ b/mysql-test/r/rpl_sp.result
@@ -31,7 +31,7 @@ declare b int;
set b = 8;
insert into t1 values (b);
insert into t1 values (unix_timestamp());
-end @ # #
+end root@localhost # #
set timestamp=1000000000;
call foo();
select * from t1;
@@ -118,7 +118,7 @@ select * from mysql.proc where name="foo4" and db='mysqltest1';
db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment
mysqltest1 foo4 PROCEDURE foo4 SQL CONTAINS_SQL YES DEFINER begin
insert into t2 values(20),(20);
-end @ # #
+end root@localhost # #
drop procedure foo4;
select * from mysql.proc where name="foo4" and db='mysqltest1';
db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment
@@ -223,13 +223,13 @@ select * from mysql.proc where db='mysqltest1';
db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment
mysqltest1 fn1 FUNCTION fn1 SQL NO_SQL NO DEFINER int(11) begin
return unix_timestamp();
-end @ # #
+end root@localhost # #
mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin
return unix_timestamp();
-end @ # #
+end zedjzlcsjhd@localhost # #
mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin
return 0;
-end @ # #
+end root@localhost # #
delete from t2;
alter table t2 add unique (a);
drop function fn1;
@@ -274,7 +274,7 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # drop database if exists mysqltest1
master-bin.000001 # Query 1 # create database mysqltest1
master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a varchar(100))
-master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo()
begin
declare b int;
set b = 8;
@@ -284,19 +284,19 @@ end
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8))
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp())
master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1
-master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo2()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo2()
select * from mysqltest1.t1
master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo2 contains sql
master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1
master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int)
master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 like t1
-master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo3()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo3()
deterministic
insert into t1 values (15)
master-bin.000001 # Query 1 # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1
master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1
master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1
-master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo4()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` procedure foo4()
deterministic
begin
insert into t2 values(3);
@@ -311,7 +311,7 @@ master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5)
master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2
master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a)
master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4
-master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo4()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo4()
deterministic
begin
insert into t2 values(20),(20);
@@ -321,7 +321,7 @@ master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4
master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo
master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo2
master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo3
-master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1(x int)
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int)
returns int
deterministic
begin
@@ -332,7 +332,7 @@ master-bin.000001 # Query 1 # use `mysqltest1`; delete t1,t2 from t1,t2
master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(20)
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21))
master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1
-master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1()
returns int
no sql
begin
@@ -340,13 +340,13 @@ return unix_timestamp();
end
master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(fn1())
-master-bin.000001 # Query 1 # use `mysqltest1`; create function fn2()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` function fn2()
returns int
no sql
begin
return unix_timestamp();
end
-master-bin.000001 # Query 1 # use `mysqltest1`; create function fn3()
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn3()
returns int
not deterministic
reads sql data
@@ -356,7 +356,7 @@ end
master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2
master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a)
master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1
-master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1(x int)
+master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int)
returns int
begin
insert into t2 values(x),(x);
diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result
index ccd880c1e07..b9b20b82acd 100644
--- a/mysql-test/r/rpl_trigger.result
+++ b/mysql-test/r/rpl_trigger.result
@@ -102,7 +102,7 @@ t1_first root@localhost
SELECT routine_name, definer
FROM information_schema.routines;
routine_name definer
-bug12480 @
+bug12480 root@localhost
SELECT trigger_name, definer
FROM information_schema.triggers;
trigger_name definer
@@ -855,3 +855,44 @@ f3
drop trigger trg11;
drop table t21,t31;
drop table t11;
+STOP SLAVE;
+FLUSH LOGS;
+RESET SLAVE;
+START SLAVE;
+SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0;
+MASTER_POS_WAIT('master-bin.000001', 513) >= 0
+1
+SHOW TABLES;
+Tables_in_test
+t1
+t2
+SHOW TRIGGERS;
+Trigger Event Table Statement Timing Created sql_mode Definer
+trg1 INSERT t1 INSERT INTO t2 VALUES(CURRENT_USER()) AFTER NULL
+SELECT * FROM t1;
+c
+1
+SELECT * FROM t2;
+s
+@
+INSERT INTO t1 VALUES(2);
+SELECT * FROM t1;
+c
+1
+2
+SELECT * FROM t2;
+s
+@
+root@localhost
+DROP TRIGGER trg1;
+Warnings:
+Warning 1454 No definer attribute for trigger 'test'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
+DROP TABLE t1;
+DROP TABLE t2;
+STOP SLAVE;
+RESET SLAVE;
+SHOW TABLES;
+Tables_in_test
+SHOW TRIGGERS;
+Trigger Event Table Statement Timing Created sql_mode Definer
+RESET MASTER;
diff --git a/mysql-test/r/skip_grants.result b/mysql-test/r/skip_grants.result
index 95464ee4ce5..6714fa9d217 100644
--- a/mysql-test/r/skip_grants.result
+++ b/mysql-test/r/skip_grants.result
@@ -2,10 +2,6 @@ drop table if exists t1,v1;
drop view if exists t1,v1;
drop procedure if exists f1;
use test;
-create table t1 (field1 INT);
-CREATE VIEW v1 AS SELECT field1 FROM t1;
-ERROR HY000: Definer is not fully qualified
-drop table t1;
create procedure f1() select 1;
drop procedure f1;
create table t1 (a int);
@@ -15,3 +11,20 @@ drop table t1;
drop function if exists f1;
Warnings:
Note 1305 FUNCTION f1 does not exist
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(c INT);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1
+FOR EACH ROW
+SET @a = 1;
+CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE DEFINER=a@b TRIGGER ti_ai AFTER INSERT ON t1
+FOR EACH ROW
+SET @b = 1;
+CREATE DEFINER=a@b VIEW v2 AS SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DROP TRIGGER ti_ai;
+DROP VIEW v1;
+DROP VIEW v2;
+DROP TABLE t1;
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
index d8abc387677..896b6fa572c 100644
--- a/mysql-test/r/sp-security.result
+++ b/mysql-test/r/sp-security.result
@@ -323,3 +323,99 @@ Warning 1287 'SHOW INNODB STATUS' is deprecated; use 'SHOW ENGINE INNODB STATUS'
GRANT EXECUTE ON PROCEDURE p1 TO user_bug7787@localhost;
DROP DATABASE db_bug7787;
use test;
+
+---> connection: root
+DROP DATABASE IF EXISTS mysqltest;
+CREATE DATABASE mysqltest;
+CREATE USER mysqltest_1@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost;
+CREATE USER mysqltest_2@localhost;
+GRANT SUPER ON *.* TO mysqltest_2@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost;
+
+---> connection: mysqltest_2_con
+use mysqltest;
+CREATE PROCEDURE wl2897_p1() SELECT 1;
+CREATE FUNCTION wl2897_f1() RETURNS INT RETURN 1;
+
+---> connection: mysqltest_1_con
+use mysqltest;
+CREATE DEFINER=root@localhost PROCEDURE wl2897_p2() SELECT 2;
+ERROR 42000: Access denied; you need the SUPER privilege for this operation
+CREATE DEFINER=root@localhost FUNCTION wl2897_f2() RETURNS INT RETURN 2;
+ERROR 42000: Access denied; you need the SUPER privilege for this operation
+
+---> connection: mysqltest_2_con
+use mysqltest;
+CREATE DEFINER='a @ b @ c'@localhost PROCEDURE wl2897_p3() SELECT 3;
+Warnings:
+Note 1449 There is no 'a @ b @ c'@'localhost' registered
+CREATE DEFINER='a @ b @ c'@localhost FUNCTION wl2897_f3() RETURNS INT RETURN 3;
+Warnings:
+Note 1449 There is no 'a @ b @ c'@'localhost' registered
+
+---> connection: con1root
+use mysqltest;
+SHOW CREATE PROCEDURE wl2897_p1;
+Procedure sql_mode Create Procedure
+wl2897_p1 CREATE DEFINER=`mysqltest_2`@`localhost` PROCEDURE `wl2897_p1`()
+SELECT 1
+SHOW CREATE PROCEDURE wl2897_p3;
+Procedure sql_mode Create Procedure
+wl2897_p3 CREATE DEFINER=`a @ b @ c`@`localhost` PROCEDURE `wl2897_p3`()
+SELECT 3
+SHOW CREATE FUNCTION wl2897_f1;
+Function sql_mode Create Function
+wl2897_f1 CREATE DEFINER=`mysqltest_2`@`localhost` FUNCTION `wl2897_f1`() RETURNS int(11)
+RETURN 1
+SHOW CREATE FUNCTION wl2897_f3;
+Function sql_mode Create Function
+wl2897_f3 CREATE DEFINER=`a @ b @ c`@`localhost` FUNCTION `wl2897_f3`() RETURNS int(11)
+RETURN 3
+DROP USER mysqltest_1@localhost;
+DROP USER mysqltest_2@localhost;
+DROP DATABASE mysqltest;
+
+---> connection: root
+DROP DATABASE IF EXISTS mysqltest;
+CREATE DATABASE mysqltest;
+CREATE USER mysqltest_1@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost;
+CREATE USER mysqltest_2@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost;
+
+---> connection: mysqltest_1_con
+use mysqltest;
+CREATE PROCEDURE bug13198_p1()
+SELECT 1;
+CREATE FUNCTION bug13198_f1() RETURNS INT
+RETURN 1;
+CALL bug13198_p1();
+1
+1
+SELECT bug13198_f1();
+bug13198_f1()
+1
+
+---> connection: mysqltest_2_con
+use mysqltest;
+CALL bug13198_p1();
+1
+1
+SELECT bug13198_f1();
+bug13198_f1()
+1
+
+---> connection: root
+DROP USER mysqltest_1@localhost;
+
+---> connection: mysqltest_2_con
+use mysqltest;
+CALL bug13198_p1();
+ERROR HY000: There is no 'mysqltest_1'@'localhost' registered
+SELECT bug13198_f1();
+ERROR HY000: There is no 'mysqltest_1'@'localhost' registered
+
+---> connection: root
+DROP USER mysqltest_2@localhost;
+DROP DATABASE mysqltest;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index e6a22867db6..b03c49b72e7 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -788,7 +788,7 @@ comment 'Characteristics procedure test'
insert into t1 values ("chistics", 1)|
show create procedure chistics|
Procedure sql_mode Create Procedure
-chistics CREATE PROCEDURE `chistics`()
+chistics CREATE DEFINER=`root`@`localhost` PROCEDURE `chistics`()
MODIFIES SQL DATA
COMMENT 'Characteristics procedure test'
insert into t1 values ("chistics", 1)
@@ -800,7 +800,7 @@ delete from t1|
alter procedure chistics sql security invoker|
show create procedure chistics|
Procedure sql_mode Create Procedure
-chistics CREATE PROCEDURE `chistics`()
+chistics CREATE DEFINER=`root`@`localhost` PROCEDURE `chistics`()
MODIFIES SQL DATA
SQL SECURITY INVOKER
COMMENT 'Characteristics procedure test'
@@ -815,7 +815,7 @@ comment 'Characteristics procedure test'
return 42|
show create function chistics|
Function sql_mode Create Function
-chistics CREATE FUNCTION `chistics`() RETURNS int(11)
+chistics CREATE DEFINER=`root`@`localhost` FUNCTION `chistics`() RETURNS int(11)
DETERMINISTIC
SQL SECURITY INVOKER
COMMENT 'Characteristics procedure test'
@@ -828,7 +828,7 @@ no sql
comment 'Characteristics function test'|
show create function chistics|
Function sql_mode Create Function
-chistics CREATE FUNCTION `chistics`() RETURNS int(11)
+chistics CREATE DEFINER=`root`@`localhost` FUNCTION `chistics`() RETURNS int(11)
NO SQL
DETERMINISTIC
SQL SECURITY INVOKER
@@ -1287,7 +1287,7 @@ end while;
end|
show create procedure opp|
Procedure sql_mode Create Procedure
-opp CREATE PROCEDURE `opp`(n bigint unsigned, out pp bool)
+opp CREATE DEFINER=`root`@`localhost` PROCEDURE `opp`(n bigint unsigned, out pp bool)
begin
declare r double;
declare b, s bigint unsigned default 0;
@@ -1386,7 +1386,7 @@ alter procedure bar comment "3333333333"|
alter procedure bar|
show create procedure bar|
Procedure sql_mode Create Procedure
-bar CREATE PROCEDURE `bar`(x char(16), y int)
+bar CREATE DEFINER=`root`@`localhost` PROCEDURE `bar`(x char(16), y int)
COMMENT '3333333333'
insert into test.t1 values (x, y)
show procedure status like 'bar'|
@@ -1966,13 +1966,13 @@ Db Name Type Definer Modified Created Security_type Comment
test bug2267_4 FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call bug2267_3()|
Procedure sql_mode Create Procedure
-bug2267_1 CREATE PROCEDURE `bug2267_1`()
+bug2267_1 CREATE DEFINER=`root`@`localhost` PROCEDURE `bug2267_1`()
begin
show procedure status;
end
call bug2267_4()|
Function sql_mode Create Function
-bug2267_4 CREATE FUNCTION `bug2267_4`() RETURNS int(11)
+bug2267_4 CREATE DEFINER=`root`@`localhost` FUNCTION `bug2267_4`() RETURNS int(11)
return 100
drop procedure bug2267_1|
drop procedure bug2267_2|
@@ -2333,20 +2333,20 @@ return x || y$
set @@sql_mode = ''|
show create procedure bug2564_1|
Procedure sql_mode Create Procedure
-bug2564_1 CREATE PROCEDURE `bug2564_1`()
+bug2564_1 CREATE DEFINER=`root`@`localhost` PROCEDURE `bug2564_1`()
COMMENT 'Joe''s procedure'
insert into `t1` values ("foo", 1)
show create procedure bug2564_2|
Procedure sql_mode Create Procedure
-bug2564_2 ANSI_QUOTES CREATE PROCEDURE "bug2564_2"()
+bug2564_2 ANSI_QUOTES CREATE DEFINER="root"@"localhost" PROCEDURE "bug2564_2"()
insert into "t1" values ('foo', 1)
show create function bug2564_3|
Function sql_mode Create Function
-bug2564_3 CREATE FUNCTION `bug2564_3`(x int, y int) RETURNS int(11)
+bug2564_3 CREATE DEFINER=`root`@`localhost` FUNCTION `bug2564_3`(x int, y int) RETURNS int(11)
return x || y
show create function bug2564_4|
Function sql_mode Create Function
-bug2564_4 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI CREATE FUNCTION "bug2564_4"(x int, y int) RETURNS int(11)
+bug2564_4 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI CREATE DEFINER="root"@"localhost" FUNCTION "bug2564_4"(x int, y int) RETURNS int(11)
return x || y
drop procedure bug2564_1|
drop procedure bug2564_2|
@@ -4056,7 +4056,7 @@ return 42;
end */;;
show create function bug14723;;
Function sql_mode Create Function
-bug14723 CREATE FUNCTION `bug14723`() RETURNS bigint(20)
+bug14723 CREATE DEFINER=`root`@`localhost` FUNCTION `bug14723`() RETURNS bigint(20)
main_loop: begin
return 42;
end
@@ -4069,7 +4069,7 @@ select 42;
end */;;
show create procedure bug14723;;
Procedure sql_mode Create Procedure
-bug14723 CREATE PROCEDURE `bug14723`()
+bug14723 CREATE DEFINER=`root`@`localhost` PROCEDURE `bug14723`()
main_loop: begin
select 42;
end
diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result
index 66df424919b..b05680f9c54 100644
--- a/mysql-test/r/sql_mode.result
+++ b/mysql-test/r/sql_mode.result
@@ -445,23 +445,23 @@ SET @@SQL_MODE='';
create function `foo` () returns int return 5;
show create function `foo`;
Function sql_mode Create Function
-foo CREATE FUNCTION `foo`() RETURNS int(11)
+foo CREATE DEFINER=`root`@`localhost` FUNCTION `foo`() RETURNS int(11)
return 5
SET @@SQL_MODE='ANSI_QUOTES';
show create function `foo`;
Function sql_mode Create Function
-foo CREATE FUNCTION `foo`() RETURNS int(11)
+foo CREATE DEFINER=`root`@`localhost` FUNCTION `foo`() RETURNS int(11)
return 5
drop function `foo`;
create function `foo` () returns int return 5;
show create function `foo`;
Function sql_mode Create Function
-foo ANSI_QUOTES CREATE FUNCTION "foo"() RETURNS int(11)
+foo ANSI_QUOTES CREATE DEFINER="root"@"localhost" FUNCTION "foo"() RETURNS int(11)
return 5
SET @@SQL_MODE='';
show create function `foo`;
Function sql_mode Create Function
-foo ANSI_QUOTES CREATE FUNCTION "foo"() RETURNS int(11)
+foo ANSI_QUOTES CREATE DEFINER="root"@"localhost" FUNCTION "foo"() RETURNS int(11)
return 5
drop function `foo`;
SET @@SQL_MODE='';
diff --git a/mysql-test/std_data/bug16266.000001 b/mysql-test/std_data/bug16266.000001
new file mode 100644
index 00000000000..1b24d231511
--- /dev/null
+++ b/mysql-test/std_data/bug16266.000001
Binary files differ
diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test
index f3db1cb5841..90822e0654c 100644
--- a/mysql-test/t/rpl_trigger.test
+++ b/mysql-test/t/rpl_trigger.test
@@ -162,6 +162,7 @@ use test;
drop table t1,t2;
drop database other;
+
#
# Test specific triggers including SELECT into var with replication
# BUG#13227:
@@ -257,6 +258,79 @@ while ($rnd)
}
+#
+# BUG#16266: Definer is not fully qualified error during replication.
+#
+# The idea of this test is to emulate replication of a trigger from the old
+# master (master w/o "DEFINER in triggers" support) to the new slave and check
+# that:
+# 1. the trigger on the slave will be replicated w/o errors;
+# 2. the trigger on the slave will be non-SUID (will have no DEFINER);
+# 3. the trigger can be activated later on the slave w/o errors.
+#
+# In order to emulate this kind of replication, we make the slave playing the binlog,
+# recorded by 5.0.16 master. This binlog contains the following statements:
+# CREATE TABLE t1(c INT);
+# CREATE TABLE t2(s CHAR(200));
+# CREATE TRIGGER trg1 AFTER INSERT ON t1
+# FOR EACH ROW
+# INSERT INTO t2 VALUES(CURRENT_USER());
+# INSERT INTO t1 VALUES(1);
+#
+
+# 1. Check that the trigger's replication is succeeded.
+
+# Stop the slave.
+
+connection slave;
+STOP SLAVE;
+
+# Replace master's binlog.
+
+connection master;
+FLUSH LOGS;
+exec cp $MYSQL_TEST_DIR/std_data/bug16266.000001 $MYSQLTEST_VARDIR/log/master-bin.000001;
+
+# Make the slave to replay the new binlog.
+
+connection slave;
+RESET SLAVE;
+START SLAVE;
+
+SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0;
+
+# Check that the replication succeeded.
+
+SHOW TABLES;
+SHOW TRIGGERS;
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+# 2. Check that the trigger is non-SUID on the slave;
+# 3. Check that the trigger can be activated on the slave.
+
+INSERT INTO t1 VALUES(2);
+
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+# That's all, cleanup.
+
+DROP TRIGGER trg1;
+DROP TABLE t1;
+DROP TABLE t2;
+
+STOP SLAVE;
+RESET SLAVE;
+
+# The master should be clean.
+
+connection master;
+SHOW TABLES;
+SHOW TRIGGERS;
+
+RESET MASTER;
+
#
# End of tests
diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test
index 27220c9b507..93e052d8c71 100644
--- a/mysql-test/t/skip_grants.test
+++ b/mysql-test/t/skip_grants.test
@@ -9,14 +9,6 @@ drop procedure if exists f1;
use test;
#
-# test that we can create VIEW if privileges check switched off
-#
-create table t1 (field1 INT);
--- error ER_MALFORMED_DEFINER
-CREATE VIEW v1 AS SELECT field1 FROM t1;
-drop table t1;
-
-#
# Test that we can create and drop procedure without warnings
# see bug#9993
#
@@ -33,3 +25,48 @@ drop table t1;
# BUG#17595: DROP FUNCTION IF EXISTS f1 crashes server
drop function if exists f1;
+
+#
+# BUG#16777: Can not create trigger nor view w/o definer if --skip-grant-tables
+# specified
+#
+# Also, a test that we can create VIEW if privileges check switched off has
+# been moved here.
+#
+
+# Prepare.
+
+--disable_warnings
+
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+
+DROP TABLE IF EXISTS t1;
+
+--enable_warnings
+
+# Test case.
+
+CREATE TABLE t1(c INT);
+
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1
+ FOR EACH ROW
+ SET @a = 1;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+CREATE DEFINER=a@b TRIGGER ti_ai AFTER INSERT ON t1
+ FOR EACH ROW
+ SET @b = 1;
+
+CREATE DEFINER=a@b VIEW v2 AS SELECT * FROM t1;
+
+# Cleanup.
+
+DROP TRIGGER t1_bi;
+DROP TRIGGER ti_ai;
+
+DROP VIEW v1;
+DROP VIEW v2;
+
+DROP TABLE t1;
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
index 19f94a32d9c..f369dc64b0e 100644
--- a/mysql-test/t/sp-security.test
+++ b/mysql-test/t/sp-security.test
@@ -547,4 +547,200 @@ GRANT EXECUTE ON PROCEDURE p1 TO user_bug7787@localhost;
DROP DATABASE db_bug7787;
use test;
+
+#
+# WL#2897: Complete definer support in the stored routines.
+#
+# The following cases are tested:
+# 1. check that if DEFINER-clause is not explicitly specified, stored routines
+# are created with CURRENT_USER privileges;
+# 2. check that if DEFINER-clause specifies non-current user, SUPER privilege
+# is required to create a stored routine;
+# 3. check that if DEFINER-clause specifies non-existent user, a warning is
+# emitted.
+# 4. check that SHOW CREATE PROCEDURE | FUNCTION works correctly;
+#
+# The following cases are tested in other test suites:
+# - check that mysqldump dumps new attribute correctly;
+# - check that slave replicates CREATE-statements with explicitly specified
+# DEFINER correctly.
+#
+
+# Setup the environment.
+
+--echo
+--echo ---> connection: root
+--connection con1root
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest;
+--enable_warnings
+
+CREATE DATABASE mysqltest;
+
+CREATE USER mysqltest_1@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost;
+
+CREATE USER mysqltest_2@localhost;
+GRANT SUPER ON *.* TO mysqltest_2@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost;
+
+--connect (mysqltest_2_con,localhost,mysqltest_2,,mysqltest)
+--connect (mysqltest_1_con,localhost,mysqltest_1,,mysqltest)
+
+# test case (1).
+
+--echo
+--echo ---> connection: mysqltest_2_con
+--connection mysqltest_2_con
+
+use mysqltest;
+
+CREATE PROCEDURE wl2897_p1() SELECT 1;
+
+CREATE FUNCTION wl2897_f1() RETURNS INT RETURN 1;
+
+# test case (2).
+
+--echo
+--echo ---> connection: mysqltest_1_con
+--connection mysqltest_1_con
+
+use mysqltest;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE DEFINER=root@localhost PROCEDURE wl2897_p2() SELECT 2;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE DEFINER=root@localhost FUNCTION wl2897_f2() RETURNS INT RETURN 2;
+
+# test case (3).
+
+--echo
+--echo ---> connection: mysqltest_2_con
+--connection mysqltest_2_con
+
+use mysqltest;
+
+CREATE DEFINER='a @ b @ c'@localhost PROCEDURE wl2897_p3() SELECT 3;
+
+CREATE DEFINER='a @ b @ c'@localhost FUNCTION wl2897_f3() RETURNS INT RETURN 3;
+
+# test case (4).
+
+--echo
+--echo ---> connection: con1root
+--connection con1root
+
+use mysqltest;
+
+SHOW CREATE PROCEDURE wl2897_p1;
+SHOW CREATE PROCEDURE wl2897_p3;
+
+SHOW CREATE FUNCTION wl2897_f1;
+SHOW CREATE FUNCTION wl2897_f3;
+
+# Cleanup.
+
+DROP USER mysqltest_1@localhost;
+DROP USER mysqltest_2@localhost;
+
+DROP DATABASE mysqltest;
+
+--disconnect mysqltest_1_con
+--disconnect mysqltest_2_con
+
+
+#
+# BUG#13198: SP executes if definer does not exist
+#
+
+# Prepare environment.
+
+--echo
+--echo ---> connection: root
+--connection con1root
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest;
+--enable_warnings
+
+CREATE DATABASE mysqltest;
+
+CREATE USER mysqltest_1@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_1@localhost;
+
+CREATE USER mysqltest_2@localhost;
+GRANT ALL PRIVILEGES ON mysqltest.* TO mysqltest_2@localhost;
+
+--connect (mysqltest_1_con,localhost,mysqltest_1,,mysqltest)
+--connect (mysqltest_2_con,localhost,mysqltest_2,,mysqltest)
+
+# Create a procedure/function under u1.
+
+--echo
+--echo ---> connection: mysqltest_1_con
+--connection mysqltest_1_con
+
+use mysqltest;
+
+CREATE PROCEDURE bug13198_p1()
+ SELECT 1;
+
+CREATE FUNCTION bug13198_f1() RETURNS INT
+ RETURN 1;
+
+CALL bug13198_p1();
+
+SELECT bug13198_f1();
+
+# Check that u2 can call the procedure/function.
+
+--echo
+--echo ---> connection: mysqltest_2_con
+--connection mysqltest_2_con
+
+use mysqltest;
+
+CALL bug13198_p1();
+
+SELECT bug13198_f1();
+
+# Drop user u1 (definer of the object);
+
+--echo
+--echo ---> connection: root
+--connection con1root
+
+--disconnect mysqltest_1_con
+
+DROP USER mysqltest_1@localhost;
+
+# Check that u2 can not call the procedure/function.
+
+--echo
+--echo ---> connection: mysqltest_2_con
+--connection mysqltest_2_con
+
+use mysqltest;
+
+--error ER_NO_SUCH_USER
+CALL bug13198_p1();
+
+--error ER_NO_SUCH_USER
+SELECT bug13198_f1();
+
+# Cleanup.
+
+--echo
+--echo ---> connection: root
+--connection con1root
+
+--disconnect mysqltest_2_con
+
+DROP USER mysqltest_2@localhost;
+
+DROP DATABASE mysqltest;
+
+
# End of 5.0 bugs.
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 2c817ae54c2..a43307edf27 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -530,7 +530,8 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables);
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
TABLE_LIST *create_table);
-bool get_default_definer(THD *thd, LEX_USER *definer);
+void get_default_definer(THD *thd, LEX_USER *definer);
+LEX_USER *create_default_definer(THD *thd);
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
enum enum_mysql_completiontype {
diff --git a/sql/sp.cc b/sql/sp.cc
index ce0282bf810..e4489af1fdd 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -21,6 +21,8 @@
#include "sp_cache.h"
#include "sql_trigger.h"
+#include <my_user.h>
+
static bool
create_string(THD *thd, String *buf,
int sp_type,
@@ -28,7 +30,9 @@ create_string(THD *thd, String *buf,
const char *params, ulong paramslen,
const char *returns, ulong returnslen,
const char *body, ulong bodylen,
- st_sp_chistics *chistics);
+ st_sp_chistics *chistics,
+ const LEX_STRING *definer_user,
+ const LEX_STRING *definer_host);
static int
db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
ulong sql_mode, const char *params, const char *returns,
@@ -406,6 +410,15 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
ulong old_sql_mode= thd->variables.sql_mode;
ha_rows old_select_limit= thd->variables.select_limit;
sp_rcontext *old_spcont= thd->spcont;
+
+ char definer_user_name_holder[USERNAME_LENGTH + 1];
+ LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder,
+ USERNAME_LENGTH);
+
+ char definer_host_name_holder[HOSTNAME_LENGTH + 1];
+ LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder,
+ HOSTNAME_LENGTH);
+
int ret;
thd->variables.sql_mode= sql_mode;
@@ -414,14 +427,25 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
thd->lex= &newlex;
newlex.current_select= NULL;
+ parse_user(definer, strlen(definer),
+ definer_user_name.str, &definer_user_name.length,
+ definer_host_name.str, &definer_host_name.length);
+
defstr.set_charset(system_charset_info);
+
+ /*
+ We have to add DEFINER clause and provide proper routine characterstics in
+ routine definition statement that we build here to be able to use this
+ definition for SHOW CREATE PROCEDURE later.
+ */
+
if (!create_string(thd, &defstr,
type,
name,
params, strlen(params),
returns, strlen(returns),
body, strlen(body),
- &chistics))
+ &chistics, &definer_user_name, &definer_host_name))
{
ret= SP_INTERNAL_ERROR;
goto end;
@@ -449,7 +473,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
goto end;
*sphp= newlex.sphead;
- (*sphp)->set_definer((char*) definer, (uint) strlen(definer));
+ (*sphp)->set_definer(&definer_user_name, &definer_host_name);
(*sphp)->set_info(created, modified, &chistics, sql_mode);
(*sphp)->optimize();
}
@@ -500,8 +524,10 @@ db_create_routine(THD *thd, int type, sp_head *sp)
else
{
restore_record(table, s->default_values); // Get default values for fields
- strxmov(definer, thd->security_ctx->priv_user, "@",
- thd->security_ctx->priv_host, NullS);
+
+ /* NOTE: all needed privilege checks have been already done. */
+ strxmov(definer, thd->lex->definer->user.str, "@",
+ thd->lex->definer->host.str, NullS);
if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
{
@@ -592,8 +618,17 @@ db_create_routine(THD *thd, int type, sp_head *sp)
else if (mysql_bin_log.is_open())
{
thd->clear_error();
+
+ String log_query;
+ log_query.set_charset(system_charset_info);
+ log_query.append(STRING_WITH_LEN("CREATE "));
+ append_definer(thd, &log_query, &thd->lex->definer->user,
+ &thd->lex->definer->host);
+ log_query.append(thd->lex->stmt_definition_begin);
+
/* Such a statement can always go directly to binlog, no trans cache */
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0,
+ FALSE);
mysql_bin_log.write(&qinfo);
}
@@ -1723,14 +1758,18 @@ create_string(THD *thd, String *buf,
const char *params, ulong paramslen,
const char *returns, ulong returnslen,
const char *body, ulong bodylen,
- st_sp_chistics *chistics)
+ st_sp_chistics *chistics,
+ const LEX_STRING *definer_user,
+ const LEX_STRING *definer_host)
{
/* Make some room to begin with */
if (buf->alloc(100 + name->m_qname.length + paramslen + returnslen + bodylen +
- chistics->comment.length))
+ chistics->comment.length + 10 /* length of " DEFINER= "*/ +
+ USER_HOST_BUFF_SIZE))
return FALSE;
buf->append(STRING_WITH_LEN("CREATE "));
+ append_definer(thd, buf, definer_user, definer_host);
if (type == TYPE_ENUM_FUNCTION)
buf->append(STRING_WITH_LEN("FUNCTION "));
else
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index f7572a374f1..c0b566f9b9b 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1810,19 +1810,27 @@ sp_head::set_info(longlong created, longlong modified,
void
sp_head::set_definer(const char *definer, uint definerlen)
{
- uint user_name_len;
- char user_name_str[USERNAME_LENGTH + 1];
- uint host_name_len;
- char host_name_str[HOSTNAME_LENGTH + 1];
+ char user_name_holder[USERNAME_LENGTH + 1];
+ LEX_STRING_WITH_INIT user_name(user_name_holder, USERNAME_LENGTH);
- parse_user(definer, definerlen, user_name_str, &user_name_len,
- host_name_str, &host_name_len);
+ char host_name_holder[HOSTNAME_LENGTH + 1];
+ LEX_STRING_WITH_INIT host_name(host_name_holder, HOSTNAME_LENGTH);
- m_definer_user.str= strmake_root(mem_root, user_name_str, user_name_len);
- m_definer_user.length= user_name_len;
+ parse_user(definer, definerlen, user_name.str, &user_name.length,
+ host_name.str, &host_name.length);
- m_definer_host.str= strmake_root(mem_root, host_name_str, host_name_len);
- m_definer_host.length= host_name_len;
+ set_definer(&user_name, &host_name);
+}
+
+
+void
+sp_head::set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name)
+{
+ m_definer_user.str= strmake_root(mem_root, user_name->str, user_name->length);
+ m_definer_user.length= user_name->length;
+
+ m_definer_host.str= strmake_root(mem_root, host_name->str, host_name->length);
+ m_definer_host.length= host_name->length;
}
@@ -3163,24 +3171,9 @@ sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup)
sp->m_definer_host.str,
sp->m_db.str))
{
-#ifdef NOT_YET_REPLICATION_SAFE
- /*
- Until we don't properly replicate information about stored routine
- definer with stored routine creation statement all stored routines
- on slave are created under ''@'' definer. Therefore we won't be able
- to run any routine which was replicated from master on slave server
- if we emit error here. This will cause big problems for users
- who use slave for fail-over. So until we fully implement WL#2897
- "Complete definer support in the stored routines" we run suid
- stored routines for which we were unable to find definer under
- invoker security context.
- */
my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str,
sp->m_definer_host.str);
return TRUE;
-#else
- return FALSE;
-#endif
}
*backup= thd->security_ctx;
thd->security_ctx= &sp->m_security_ctx;
diff --git a/sql/sp_head.h b/sql/sp_head.h
index a4dd68ee4a3..64d9167fb17 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -302,6 +302,7 @@ public:
st_sp_chistics *chistics, ulong sql_mode);
void set_definer(const char *definer, uint definerlen);
+ void set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name);
void reset_thd_mem_root(THD *thd);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7b2ea359fb2..8db059ae2fa 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -909,12 +909,16 @@ typedef struct st_lex
SQL_LIST trg_table_fields;
/*
- trigger_definition_begin points to the beginning of the word "TRIGGER" in
- CREATE TRIGGER statement. This is used to add possibly omitted DEFINER
- clause to the trigger definition statement before dumping it to the
- binlog.
+ stmt_definition_begin is intended to point to the next word after
+ DEFINER-clause in the following statements:
+ - CREATE TRIGGER (points to "TRIGGER");
+ - CREATE PROCEDURE (points to "PROCEDURE");
+ - CREATE FUNCTION (points to "FUNCTION" or "AGGREGATE");
+
+ This pointer is required to add possibly omitted DEFINER-clause to the
+ DDL-statement before dumping it to the binlog.
*/
- const char *trigger_definition_begin;
+ const char *stmt_definition_begin;
/*
If non-0 then indicates that query requires prelocking and points to
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b2066953cf5..527a6a67811 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4146,6 +4146,90 @@ end_with_restore_list:
#endif
/*
+ If the definer is not specified, this means that CREATE-statement missed
+ DEFINER-clause. DEFINER-clause can be missed in two cases:
+
+ - The user submitted a statement w/o the clause. This is a normal
+ case, we should assign CURRENT_USER as definer.
+
+ - Our slave received an updated from the master, that does not
+ replicate definer for stored rountines. We should also assign
+ CURRENT_USER as definer here, but also we should mark this routine
+ as NON-SUID. This is essential for the sake of backward
+ compatibility.
+
+ The problem is the slave thread is running under "special" user (@),
+ that actually does not exist. In the older versions we do not fail
+ execution of a stored routine if its definer does not exist and
+ continue the execution under the authorization of the invoker
+ (BUG#13198). And now if we try to switch to slave-current-user (@),
+ we will fail.
+
+ Actually, this leads to the inconsistent state of master and
+ slave (different definers, different SUID behaviour), but it seems,
+ this is the best we can do.
+ */
+
+ if (!lex->definer)
+ {
+ bool res= FALSE;
+ Query_arena original_arena;
+ Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
+
+ if (!(lex->definer= create_default_definer(thd)))
+ res= TRUE;
+
+ if (ps_arena)
+ thd->restore_active_arena(ps_arena, &original_arena);
+
+ if (res)
+ {
+ /* Error has been already reported. */
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+
+ if (thd->slave_thread)
+ lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
+ }
+
+ /*
+ If the specified definer differs from the current user, we should check
+ that the current user has SUPER privilege (in order to create a stored
+ routine under another user one must have SUPER privilege).
+ */
+
+ else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info,
+ lex->definer->host.str,
+ thd->security_ctx->priv_host))
+ {
+ if (check_global_access(thd, SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+ }
+
+ /* Check that the specified definer exists. Emit a warning if not. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (!is_acl_user(lex->definer->host.str,
+ lex->definer->user.str))
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_SUCH_USER,
+ ER(ER_NO_SUCH_USER),
+ lex->definer->user.str,
+ lex->definer->host.str);
+ }
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+ /*
We need to copy name and db in order to use them for
check_routine_access which is called after lex->sphead has
been deleted.
@@ -7168,41 +7252,49 @@ Item *negate_expression(THD *thd, Item *expr)
/*
Set the specified definer to the default value, which is the current user in
- the thread. Also check that the current user satisfies to the definers
- requirements.
+ the thread.
SYNOPSIS
get_default_definer()
thd [in] thread handler
definer [out] definer
-
- RETURN
- error status, that is:
- - FALSE -- on success;
- - TRUE -- on error (current user can not be a definer).
*/
-bool get_default_definer(THD *thd, LEX_USER *definer)
+void get_default_definer(THD *thd, LEX_USER *definer)
{
- /* Check that current user has non-empty host name. */
-
const Security_context *sctx= thd->security_ctx;
- if (sctx->priv_host[0] == 0)
- {
- my_error(ER_MALFORMED_DEFINER, MYF(0));
- return TRUE;
- }
-
- /* Fill in. */
-
definer->user.str= (char *) sctx->priv_user;
definer->user.length= strlen(definer->user.str);
definer->host.str= (char *) sctx->priv_host;
definer->host.length= strlen(definer->host.str);
+}
- return FALSE;
+
+/*
+ Create default definer for the specified THD.
+
+ SYNOPSIS
+ create_default_definer()
+ thd [in] thread handler
+
+ RETURN
+ On success, return a valid pointer to the created and initialized
+ LEX_USER, which contains definer information.
+ On error, return 0.
+*/
+
+LEX_USER *create_default_definer(THD *thd)
+{
+ LEX_USER *definer;
+
+ if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
+ return 0;
+
+ get_default_definer(thd, definer);
+
+ return definer;
}
@@ -7218,7 +7310,7 @@ bool get_default_definer(THD *thd, LEX_USER *definer)
RETURN
On success, return a valid pointer to the created and initialized
- LEX_STRING, which contains definer information.
+ LEX_USER, which contains definer information.
On error, return 0.
*/
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index cef8c4dd1dc..024c882f8a9 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -264,8 +264,18 @@ end:
log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */
log_query.append(STRING_WITH_LEN("CREATE "));
- append_definer(thd, &log_query, &definer_user, &definer_host);
- log_query.append(thd->lex->trigger_definition_begin);
+
+ if (definer_user.str && definer_host.str)
+ {
+ /*
+ Append definer-clause if the trigger is SUID (a usual trigger in
+ new MySQL versions).
+ */
+
+ append_definer(thd, &log_query, &definer_user, &definer_host);
+ }
+
+ log_query.append(thd->lex->stmt_definition_begin);
}
/* Such a statement can always go directly to binlog, no trans cache. */
@@ -289,17 +299,30 @@ end:
LEX)
tables - table list containing one open table for which the
trigger is created.
- definer_user - [out] after a call it points to 0-terminated string,
- which contains user name part of the actual trigger
- definer. The caller is responsible to provide memory for
+ definer_user - [out] after a call it points to 0-terminated string or
+ contains the NULL-string:
+ - 0-terminated is returned if the trigger is SUID. The
+ string contains user name part of the actual trigger
+ definer.
+ - NULL-string is returned if the trigger is non-SUID.
+ Anyway, the caller is responsible to provide memory for
storing LEX_STRING object.
- definer_host - [out] after a call it points to 0-terminated string,
- which contains host name part of the actual trigger
- definer. The caller is responsible to provide memory for
+ definer_host - [out] after a call it points to 0-terminated string or
+ contains the NULL-string:
+ - 0-terminated string is returned if the trigger is
+ SUID. The string contains host name part of the
+ actual trigger definer.
+ - NULL-string is returned if the trigger is non-SUID.
+ Anyway, the caller is responsible to provide memory for
storing LEX_STRING object.
NOTE
- Assumes that trigger name is fully qualified.
+ - Assumes that trigger name is fully qualified.
+ - NULL-string means the following LEX_STRING instance:
+ { str = 0; length = 0 }.
+ - In other words, definer_user and definer_host should contain
+ simultaneously NULL-strings (non-SUID/old trigger) or valid strings
+ (SUID/new trigger).
RETURN VALUE
False - success
@@ -336,12 +359,30 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
return 1;
}
- /*
- Definer attribute of the Lex instance is always set in sql_yacc.yy when
- trigger is created.
- */
+ if (!lex->definer)
+ {
+ /*
+ DEFINER-clause is missing.
- DBUG_ASSERT(lex->definer);
+ If we are in slave thread, this means that we received CREATE TRIGGER
+ from the master, that does not support definer in triggers. So, we
+ should mark this trigger as non-SUID. Note that this does not happen
+ when we parse triggers' definitions during opening .TRG file.
+ LEX::definer is ignored in that case.
+
+ Otherwise, we should use CURRENT_USER() as definer.
+
+ NOTE: when CREATE TRIGGER statement is allowed to be executed in PS/SP,
+ it will be required to create the definer below in persistent MEM_ROOT
+ of PS/SP.
+ */
+
+ if (!thd->slave_thread)
+ {
+ if (!(lex->definer= create_default_definer(thd)))
+ return 1;
+ }
+ }
/*
If the specified definer differs from the current user, we should check
@@ -349,10 +390,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
under another user one must have SUPER privilege).
*/
- if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
- my_strcasecmp(system_charset_info,
- lex->definer->host.str,
- thd->security_ctx->priv_host))
+ if (lex->definer &&
+ (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info,
+ lex->definer->host.str,
+ thd->security_ctx->priv_host)))
{
if (check_global_access(thd, SUPER_ACL))
{
@@ -446,8 +488,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
*trg_sql_mode= thd->variables.sql_mode;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!is_acl_user(lex->definer->host.str,
- lex->definer->user.str))
+ if (lex->definer && !is_acl_user(lex->definer->host.str,
+ lex->definer->user.str))
{
push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_NOTE,
@@ -458,12 +500,30 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
}
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
- *definer_user= lex->definer->user;
- *definer_host= lex->definer->host;
+ if (lex->definer)
+ {
+ /* SUID trigger. */
+
+ *definer_user= lex->definer->user;
+ *definer_host= lex->definer->host;
- trg_definer->str= trg_definer_holder;
- trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@",
- definer_host->str, NullS) - trg_definer->str;
+ trg_definer->str= trg_definer_holder;
+ trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@",
+ definer_host->str, NullS) - trg_definer->str;
+ }
+ else
+ {
+ /* non-SUID trigger. */
+
+ definer_user->str= 0;
+ definer_user->length= 0;
+
+ definer_host->str= 0;
+ definer_host->length= 0;
+
+ trg_definer->str= (char*) "";
+ trg_definer->length= 0;
+ }
if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
(gptr)this, triggers_file_parameters, 0))
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 4f62a80cfd4..4f2a9a07705 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -208,6 +208,26 @@ bool mysql_create_view(THD *thd,
if (mode != VIEW_CREATE_NEW)
sp_cache_invalidate();
+ if (!lex->definer)
+ {
+ /*
+ DEFINER-clause is missing; we have to create default definer in
+ persistent arena to be PS/SP friendly.
+ */
+
+ Query_arena original_arena;
+ Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
+
+ if (!(lex->definer= create_default_definer(thd)))
+ res= TRUE;
+
+ if (ps_arena)
+ thd->restore_active_arena(ps_arena, &original_arena);
+
+ if (res)
+ goto err;
+ }
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
check definer of view:
@@ -815,8 +835,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER),
table->db, table->table_name);
- if (get_default_definer(thd, &table->definer))
- goto err;
+ get_default_definer(thd, &table->definer);
}
/*
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 2ce53996cfa..b6d197369cf 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -778,7 +778,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword keyword_sp
-%type <lex_user> user grant_user get_definer
+%type <lex_user> user grant_user
%type <charset>
opt_collate
@@ -833,8 +833,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
definer view_replace_or_algorithm view_replace view_algorithm_opt
- view_algorithm view_or_trigger_tail view_suid view_tail view_list_opt
- view_list view_select view_check_option trigger_tail
+ view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail
+ view_suid view_tail view_list_opt view_list view_select
+ view_check_option trigger_tail sp_tail
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -1189,81 +1190,13 @@ create:
lex->name=$4.str;
lex->create_info.options=$3;
}
- | CREATE udf_func_type FUNCTION_SYM sp_name
- {
- LEX *lex=Lex;
- lex->spname= $4;
- lex->udf.type= $2;
- }
- create_function_tail
- {}
- | CREATE PROCEDURE sp_name
- {
- LEX *lex= Lex;
- sp_head *sp;
-
- if (lex->sphead)
- {
- my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
- YYABORT;
- }
- /* Order is important here: new - reset - init */
- sp= new sp_head();
- sp->reset_thd_mem_root(YYTHD);
- sp->init(lex);
-
- sp->m_type= TYPE_ENUM_PROCEDURE;
- lex->sphead= sp;
- /*
- * We have to turn of CLIENT_MULTI_QUERIES while parsing a
- * stored procedure, otherwise yylex will chop it into pieces
- * at each ';'.
- */
- sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
- YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
- }
- '('
- {
- LEX *lex= Lex;
-
- lex->sphead->m_param_begin= lex->tok_start+1;
- }
- sp_pdparam_list
- ')'
- {
- LEX *lex= Lex;
-
- lex->sphead->m_param_end= lex->tok_start;
- bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
- }
- sp_c_chistics
- {
- LEX *lex= Lex;
-
- lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lex->tok_start;
- }
- sp_proc_stmt
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
-
- if (sp->check_backpatch(YYTHD))
- YYABORT;
- sp->init_strings(YYTHD, lex, $3);
- lex->sql_command= SQLCOM_CREATE_PROCEDURE;
- /* Restore flag if it was cleared above */
- if (sp->m_old_cmq)
- YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
- sp->restore_thd_mem_root(YYTHD);
- }
| CREATE
{
Lex->create_view_mode= VIEW_CREATE_NEW;
Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
Lex->create_view_suid= TRUE;
}
- view_or_trigger
+ view_or_trigger_or_sp
{}
| CREATE USER clear_privileges grant_list
{
@@ -8957,45 +8890,61 @@ subselect_end:
lex->nest_level--;
};
+/**************************************************************************
+
+ CREATE VIEW | TRIGGER | PROCEDURE statements.
+
+**************************************************************************/
+
+view_or_trigger_or_sp:
+ definer view_or_trigger_or_sp_tail
+ {}
+ | view_replace_or_algorithm definer view_tail
+ {}
+ ;
+
+view_or_trigger_or_sp_tail:
+ view_tail
+ {}
+ | trigger_tail
+ {}
+ | sp_tail
+ {}
+ ;
+
+/**************************************************************************
+
+ DEFINER clause support.
+
+**************************************************************************/
+
definer:
- get_definer
+ /* empty */
{
- THD *thd= YYTHD;
-
- if (! (thd->lex->definer= create_definer(thd, &$1->user, &$1->host)))
- YYABORT;
+ /*
+ We have to distinguish missing DEFINER-clause from case when
+ CURRENT_USER specified as definer explicitly in order to properly
+ handle CREATE TRIGGER statements which come to replication thread
+ from older master servers (i.e. to create non-suid trigger in this
+ case).
+ */
+ YYTHD->lex->definer= 0;
}
- ;
-
-get_definer:
- opt_current_definer
+ | DEFINER_SYM EQ CURRENT_USER optional_braces
{
- THD *thd= YYTHD;
-
- if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
- YYABORT;
-
- if (get_default_definer(thd, $$))
- YYABORT;
+ if (! (YYTHD->lex->definer= create_default_definer(YYTHD)))
+ YYABORT;
}
| DEFINER_SYM EQ ident_or_text '@' ident_or_text
{
- if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user))))
- YYABORT;
-
- $$->user= $3;
- $$->host= $5;
+ if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5)))
+ YYABORT;
}
;
-opt_current_definer:
- /* empty */
- | DEFINER_SYM EQ CURRENT_USER optional_braces
- ;
-
/**************************************************************************
- CREATE VIEW statement options.
+ CREATE VIEW statement parts.
**************************************************************************/
@@ -9029,20 +8978,6 @@ view_algorithm_opt:
{}
;
-view_or_trigger:
- definer view_or_trigger_tail
- {}
- | view_replace_or_algorithm definer view_tail
- {}
- ;
-
-view_or_trigger_tail:
- view_tail
- {}
- | trigger_tail
- {}
- ;
-
view_suid:
/* empty */
{ Lex->create_view_suid= TRUE; }
@@ -9141,7 +9076,7 @@ trigger_tail:
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
- lex->trigger_definition_begin= $2;
+ lex->stmt_definition_begin= $2;
lex->ident.str= $7;
lex->ident.length= $10 - $7;
@@ -9190,6 +9125,87 @@ trigger_tail:
}
;
+/**************************************************************************
+
+ CREATE FUNCTION | PROCEDURE statements parts.
+
+**************************************************************************/
+
+sp_tail:
+ udf_func_type remember_name FUNCTION_SYM sp_name
+ {
+ LEX *lex=Lex;
+ lex->udf.type= $1;
+ lex->stmt_definition_begin= $2;
+ lex->spname= $4;
+ }
+ create_function_tail
+ {}
+ | PROCEDURE remember_name sp_name
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
+ YYABORT;
+ }
+
+ lex->stmt_definition_begin= $2;
+
+ /* Order is important here: new - reset - init */
+ sp= new sp_head();
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(lex);
+
+ sp->m_type= TYPE_ENUM_PROCEDURE;
+ lex->sphead= sp;
+ /*
+ * We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ * stored procedure, otherwise yylex will chop it into pieces
+ * at each ';'.
+ */
+ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
+ }
+ '('
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_param_begin= lex->tok_start+1;
+ }
+ sp_pdparam_list
+ ')'
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_param_end= lex->tok_start;
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ }
+ sp_c_chistics
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_chistics= &lex->sp_chistics;
+ lex->sphead->m_body_begin= lex->tok_start;
+ }
+ sp_proc_stmt
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ if (sp->check_backpatch(YYTHD))
+ YYABORT;
+ sp->init_strings(YYTHD, lex, $3);
+ lex->sql_command= SQLCOM_CREATE_PROCEDURE;
+ /* Restore flag if it was cleared above */
+ if (sp->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ sp->restore_thd_mem_root(YYTHD);
+ }
+ ;
+
/*************************************************************************/
xa: XA_SYM begin_or_start xid opt_join_or_resume