diff options
47 files changed, 683 insertions, 421 deletions
diff --git a/include/mysqld_error.h b/include/mysqld_error.h index a3e063d4ed7..113eb07ed66 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -339,4 +339,5 @@ #define ER_SP_DUP_CURS 1320 #define ER_SP_CANT_ALTER 1321 #define ER_SP_SUBSELECT_NYI 1322 -#define ER_ERROR_MESSAGES 323 +#define ER_SP_NO_USE 1323 +#define ER_ERROR_MESSAGES 324 diff --git a/include/sql_state.h b/include/sql_state.h index f4fbe434490..c5a71daceb9 100644 --- a/include/sql_state.h +++ b/include/sql_state.h @@ -196,3 +196,4 @@ ER_SP_DUP_COND, "42000", "", ER_SP_DUP_CURS, "42000", "", /*ER_SP_CANT_ALTER*/ ER_SP_SUBSELECT_NYI, "0A000", "", +ER_SP_NO_USE, "42000", "", diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 3fa700ccf26..4645e7d9b9c 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -144,7 +144,6 @@ insert into t1 values (1); show open tables; Database Table In_use Name_locked test t1 0 0 -mysql proc 0 0 drop table t1; create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" ENGINE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed; show create table t1; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index f965cf90eb4..1877789e2b0 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -251,6 +251,10 @@ declare c cursor for select * from t1; declare c cursor for select field from t1; end| ERROR 42000: Duplicate cursor: c +create procedure u() +use sptmp; +#| +ERROR 42000: USE is not allowed in a stored procedure create procedure bug1965() begin declare c cursor for select val from t1 order by valname; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index c4fbece9d72..51439e08782 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -8,16 +8,16 @@ create table t1 ( u varchar(64), i int ); create procedure stamp(i int) insert into db1_secret.t1 values (user(), i); show procedure status like 'stamp'; -Name Type Definer Modified Created Security_type Comment -stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +Db Name Type Definer Modified Created Security_type Comment +db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER call stamp(1); select * from t1; u i root@localhost 1 -call stamp(2); +call db1_secret.stamp(2); select * from db1_secret.t1; ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret' -call stamp(3); +call db1_secret.stamp(3); select * from db1_secret.t1; ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret' select * from t1; @@ -27,8 +27,8 @@ user1@localhost 2 anon@localhost 3 alter procedure stamp sql security invoker; show procedure status like 'stamp'; -Name Type Definer Modified Created Security_type Comment -stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER +Db Name Type Definer Modified Created Security_type Comment +db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER call stamp(4); select * from t1; u i @@ -36,9 +36,9 @@ root@localhost 1 user1@localhost 2 anon@localhost 3 root@localhost 4 -call stamp(5); +call db1_secret.stamp(5); ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret' -call stamp(6); +call db1_secret.stamp(6); ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret' drop database if exists db2; create database db2; @@ -73,9 +73,9 @@ s1 0 2 2 -drop procedure stamp; -drop procedure p; -drop procedure q; +drop procedure db1_secret.stamp; +drop procedure db2.p; +drop procedure db2.q; use test; drop database db1_secret; drop database db2; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 2b91e8de270..f1fa1735ead 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -18,17 +18,6 @@ id data foo 42 delete from t1; drop procedure foo42; -create procedure u() -use sptmp; -drop database if exists sptmp; -create database sptmp; -use test; -call u(); -select database(); -database() -test -drop database sptmp; -drop procedure u; create procedure bar(x char(16), y int) insert into test.t1 values (x, y); call bar("bar", 666); @@ -746,7 +735,7 @@ delete from t1| alter procedure chistics sql security invoker name chistics2| show create procedure chistics2| Procedure Create Procedure -chistics2 CREATE PROCEDURE `chistics2`() +chistics2 CREATE PROCEDURE `test`.`chistics2`() SQL SECURITY INVOKER COMMENT 'Characteristics procedure test' insert into t1 values ("chistics", 1) @@ -763,7 +752,7 @@ chistics() alter function chistics name chistics2 comment 'Characteristics function test'| show create function chistics2| Function Create Function -chistics2 CREATE FUNCTION `chistics2`() RETURNS int +chistics2 CREATE FUNCTION `test`.`chistics2`() RETURNS int DETERMINISTIC SQL SECURITY INVOKER COMMENT 'Characteristics function test' @@ -939,23 +928,23 @@ begin show create function fac; end| call bug2267_1()| -Name Type Definer Modified Created Security_type Comment -bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER -bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER -bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER -bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +Db Name Type Definer Modified Created Security_type Comment +test bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +test bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +test bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +test bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER call bug2267_2()| -Name Type Definer Modified Created Security_type Comment -fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +Db Name Type Definer Modified Created Security_type Comment +test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER call bug2267_3()| Procedure Create Procedure -bug2267_1 CREATE PROCEDURE `bug2267_1`() +bug2267_1 CREATE PROCEDURE `test`.`bug2267_1`() begin show procedure status; end call bug2267_4()| Function Create Function -fac CREATE FUNCTION `fac`(n int unsigned) RETURNS bigint unsigned +fac CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint unsigned begin declare f bigint unsigned default 1; while n > 1 do @@ -1035,12 +1024,12 @@ n f 20 2432902008176640000 drop table fac| show function status like '%f%'| -Name Type Definer Modified Created Security_type Comment -fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +Db Name Type Definer Modified Created Security_type Comment +test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER drop procedure ifac| drop function fac| show function status like '%f%'| -Name Type Definer Modified Created Security_type Comment +Db Name Type Definer Modified Created Security_type Comment drop table if exists primes| create table primes ( i int unsigned not null primary key, @@ -1101,7 +1090,7 @@ end while; end| show create procedure opp| Procedure Create Procedure -opp CREATE PROCEDURE `opp`(n bigint unsigned, out pp bool) +opp CREATE PROCEDURE `test`.`opp`(n bigint unsigned, out pp bool) begin declare r double; declare b, s bigint unsigned default 0; @@ -1128,9 +1117,9 @@ end if; end loop; end show procedure status like '%p%'| -Name Type Definer Modified Created Security_type Comment -ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER -opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +Db Name Type Definer Modified Created Security_type Comment +test ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +test opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER call ip(200)| select * from primes where i=45 or i=100 or i=199| i p @@ -1141,7 +1130,7 @@ drop table primes| drop procedure opp| drop procedure ip| show procedure status like '%p%'| -Name Type Definer Modified Created Security_type Comment +Db Name Type Definer Modified Created Security_type Comment drop table if exists fib| create table fib ( f bigint unsigned not null )| insert into fib values (1), (1)| @@ -1191,19 +1180,19 @@ create procedure bar(x char(16), y int) comment "111111111111" sql security invoker insert into test.t1 values (x, y)| show procedure status like 'bar'| -Name Type Definer Modified Created Security_type Comment -bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER 111111111111 +Db Name Type Definer Modified Created Security_type Comment +test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER 111111111111 alter procedure bar name bar2 comment "2222222222" sql security definer| alter procedure bar2 name bar comment "3333333333"| alter procedure bar| show create procedure bar| Procedure Create Procedure -bar CREATE PROCEDURE `bar`(x char(16), y int) +bar CREATE PROCEDURE `test`.`bar`(x char(16), y int) COMMENT '3333333333' insert into test.t1 values (x, y) show procedure status like 'bar'| -Name Type Definer Modified Created Security_type Comment -bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333 +Db Name Type Definer Modified Created Security_type Comment +test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333 drop procedure bar| drop table t1; drop table t2; diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index 3134fdcf5ee..e9616232fa1 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -14,6 +14,6 @@ update t1 set n = 3; unlock tables; show status like 'Table_lock%'; Variable_name Value -Table_locks_immediate 4 +Table_locks_immediate 3 Table_locks_waited 1 drop table t1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 68a5ccdbe42..43b5c04766a 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -330,6 +330,12 @@ begin declare c cursor for select field from t1; end| +# USE is not allowed +--error 1323 +create procedure u() + use sptmp; + + # # BUG#1965 # diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index ac7477869a1..2d089e72d0b 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -24,7 +24,7 @@ create table t1 ( u varchar(64), i int ); # Our test procedure create procedure stamp(i int) insert into db1_secret.t1 values (user(), i); ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like 'stamp'; # root can, of course @@ -40,7 +40,7 @@ connect (con3anon,localhost,anon,,); connection con2user1; # This should work... -call stamp(2); +call db1_secret.stamp(2); # ...but not this --error 1044 @@ -52,7 +52,7 @@ select * from db1_secret.t1; connection con3anon; # This should work... -call stamp(3); +call db1_secret.stamp(3); # ...but not this --error 1044 @@ -68,7 +68,7 @@ select * from t1; # Change to invoker's rights # alter procedure stamp sql security invoker; ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like 'stamp'; # root still can @@ -82,7 +82,7 @@ connection con2user1; # This should not work --error 1044 -call stamp(5); +call db1_secret.stamp(5); # # Anonymous cannot @@ -91,7 +91,7 @@ connection con3anon; # This should not work --error 1044 -call stamp(6); +call db1_secret.stamp(6); # @@ -148,9 +148,9 @@ select * from t2; # Clean up connection con1root; -drop procedure stamp; -drop procedure p; -drop procedure q; +drop procedure db1_secret.stamp; +drop procedure db2.p; +drop procedure db2.q; use test; drop database db1_secret; drop database db2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index fd6cb4a300a..5dae97b371e 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -31,21 +31,6 @@ delete from t1; drop procedure foo42; -# USE test: Make sure we remain in the same DB. -create procedure u() - use sptmp; - ---disable_warnings -drop database if exists sptmp; ---enable_warnings -create database sptmp; -use test; -call u(); -select database(); -drop database sptmp; -drop procedure u; - - # Single statement, two IN params. create procedure bar(x char(16), y int) insert into test.t1 values (x, y); @@ -1094,9 +1079,9 @@ begin show create function fac; end| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' call bug2267_1()| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' call bug2267_2()| call bug2267_3()| call bug2267_4()| @@ -1178,11 +1163,11 @@ end| call ifac(20)| select * from fac| drop table fac| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show function status like '%f%'| drop procedure ifac| drop function fac| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show function status like '%f%'| @@ -1259,7 +1244,7 @@ begin end while; end| show create procedure opp| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like '%p%'| # This isn't the fastest way in the world to compute prime numbers, so @@ -1271,7 +1256,7 @@ select * from primes where i=45 or i=100 or i=199| drop table primes| drop procedure opp| drop procedure ip| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like '%p%'| @@ -1318,13 +1303,13 @@ drop procedure fib| create procedure bar(x char(16), y int) comment "111111111111" sql security invoker insert into test.t1 values (x, y)| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like 'bar'| alter procedure bar name bar2 comment "2222222222" sql security definer| alter procedure bar2 name bar comment "3333333333"| alter procedure bar| show create procedure bar| ---replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' show procedure status like 'bar'| drop procedure bar| delimiter ;| diff --git a/sql/item_func.cc b/sql/item_func.cc index d1d03b21eed..fdb0a5e5240 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3088,6 +3088,25 @@ longlong Item_func_is_used_lock::val_int() return ull->thread_id; } + +Item_func_sp::Item_func_sp(sp_name *name) + :Item_func(), m_name(name), m_sp(NULL) +{ + m_name->init_qname(current_thd); +} + +Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list) + :Item_func(list), m_name(name), m_sp(NULL) +{ + m_name->init_qname(current_thd); +} + +const char * +Item_func_sp::func_name() const +{ + return m_name->m_name.str; +} + int Item_func_sp::execute(Item **itp) { @@ -3099,7 +3118,7 @@ Item_func_sp::execute(Item **itp) #endif if (! m_sp) - m_sp= sp_find_function(thd, &m_name); + m_sp= sp_find_function(thd, m_name); if (! m_sp) DBUG_RETURN(-1); @@ -3122,7 +3141,7 @@ Item_func_sp::field_type() const DBUG_ENTER("Item_func_sp::field_type"); if (! m_sp) - m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name)); + m_sp= sp_find_function(current_thd, m_name); if (m_sp) { DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns)); @@ -3138,7 +3157,7 @@ Item_func_sp::result_type() const DBUG_PRINT("info", ("m_sp = %p", m_sp)); if (! m_sp) - m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name)); + m_sp= sp_find_function(current_thd, m_name); if (m_sp) { DBUG_RETURN(m_sp->result()); @@ -3152,7 +3171,7 @@ Item_func_sp::fix_length_and_dec() DBUG_ENTER("Item_func_sp::fix_length_and_dec"); if (! m_sp) - m_sp= sp_find_function(current_thd, &m_name); + m_sp= sp_find_function(current_thd, m_name); if (m_sp) { switch (m_sp->result()) { diff --git a/sql/item_func.h b/sql/item_func.h index 75c8b348347..e68826ca56e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1072,32 +1072,26 @@ enum Cast_target */ class sp_head; +class sp_name; class Item_func_sp :public Item_func { private: - LEX_STRING m_name; + sp_name *m_name; mutable sp_head *m_sp; int execute(Item **itp); public: - Item_func_sp(LEX_STRING name) - :Item_func(), m_name(name), m_sp(NULL) - {} + Item_func_sp(sp_name *name); - Item_func_sp(LEX_STRING name, List<Item> &list) - :Item_func(list), m_name(name), m_sp(NULL) - {} + Item_func_sp(sp_name *name, List<Item> &list); virtual ~Item_func_sp() {} - const char *func_name() const - { - return m_name.str; - } + const char *func_name() const; enum enum_field_types field_type() const; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e17847ebe24..21822e02d29 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -445,7 +445,8 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, int quick_rm_table(enum db_type base,const char *db, const char *table_name); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); -bool mysql_change_db(THD *thd,const char *name); +bool mysql_change_db(THD *thd,const char *name, + bool empty_is_ok=0, bool no_access_check=0); void mysql_parse(THD *thd,char *inBuf,uint length); bool is_update_query(enum enum_sql_command command); void free_items(Item *item); diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 117bf4b37d4..eea5912cbdf 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -335,3 +335,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index ba012e0eea3..2c2782d4cf0 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -329,3 +329,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 0349929f0d3..84bd5781ffb 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -337,3 +337,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 6bf4bde9b22..2c88e1b445f 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 03e2d4d6c90..d72d7f94309 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -331,3 +331,4 @@ character-set=latin7 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index dab2ab9f51d..227b5138e98 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 5b2378dde22..d4e42ed5d58 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -338,3 +338,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index a840e95de97..44e072bb20e 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -326,3 +326,4 @@ character-set=greek "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 0b24ca6afb8..72fdf4f8c51 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index a298baa7682..6694f220848 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index a25357ae079..896146749a9 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -328,3 +328,4 @@ character-set=ujis "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index d3799d881ed..3a92c060c67 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -326,3 +326,4 @@ character-set=euckr "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index d69d52408ff..ada0435b52a 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 5fbbaf19480..d0688b2858c 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 92572db5fdc..d0c96146441 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -330,3 +330,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 580fec472b6..71be50ba262 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -327,3 +327,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 3e6bff75591..d800906e663 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -330,3 +330,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index b04cda84efd..633e29e8c48 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -328,3 +328,4 @@ character-set=koi8r "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 2737ce26873..efda5bb12cc 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -321,3 +321,4 @@ character-set=cp1250 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index bf9fe6d3519..8fa84320a8f 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -334,3 +334,4 @@ character-set=latin2 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index fec6bbb4342..75a6d42bec8 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -328,3 +328,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 8b2892172ba..9b743acb930 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -326,3 +326,4 @@ character-set=latin1 "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 393c765a8ca..2b3587e2028 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -331,3 +331,4 @@ character-set=koi8u "Duplicate cursor: %s" "Failed to ALTER %s %s" "Subselect value not supported" +"USE is not allowed in a stored procedure" diff --git a/sql/sp.cc b/sql/sp.cc index f517504e1f5..1b58c709e4e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -23,7 +23,7 @@ static char * create_string(THD *thd, ulong *lenp, int sp_type, - char *name, ulong namelen, + sp_name *name, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, @@ -58,21 +58,26 @@ enum /* *opened=true means we opened ourselves */ static int -db_find_routine_aux(THD *thd, int type, char *name, uint namelen, +db_find_routine_aux(THD *thd, int type, sp_name *name, enum thr_lock_type ltype, TABLE **tablep, bool *opened) { TABLE *table; byte key[64+64+1]; // db, name, type uint keylen; DBUG_ENTER("db_find_routine_aux"); - DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name)); + DBUG_PRINT("enter", ("type: %d name: %*s", + type, name->m_name.length, name->m_name.str)); // Put the key used to read the row together - memset(key, (int)' ', 64); // QQ Empty db for now - keylen= namelen; + keylen= name->m_db.length; if (keylen > 64) keylen= 64; - memcpy(key+64, name, keylen); + memcpy(key, name->m_db.str, keylen); + memset(key+keylen, (int)' ', 64-keylen); // Pad with space + keylen= name->m_name.length; + if (keylen > 64) + keylen= 64; + memcpy(key+64, name->m_name.str, keylen); memset(key+64+keylen, (int)' ', 64-keylen); // Pad with space key[128]= type; keylen= sizeof(key); @@ -112,7 +117,7 @@ db_find_routine_aux(THD *thd, int type, char *name, uint namelen, static int -db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) +db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) { extern int yyparse(void *thd); TABLE *table; @@ -129,9 +134,10 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) String str(buff, sizeof(buff), &my_charset_bin); ulong sql_mode; DBUG_ENTER("db_find_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name)); + DBUG_PRINT("enter", ("type: %d name: %*s", + type, name->m_name.length, name->m_name.str)); - ret= db_find_routine_aux(thd, type, name, namelen, TL_READ, &table, &opened); + ret= db_find_routine_aux(thd, type, name, TL_READ, &table, &opened); if (ret != SP_OK) goto done; @@ -211,6 +217,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) char *defstr; ulong deflen; LEX *oldlex= thd->lex; + char olddb[128]; + char *olddbptr; enum enum_sql_command oldcmd= thd->lex->sql_command; ulong old_sql_mode= thd->variables.sql_mode; ha_rows select_limit= thd->variables.select_limit; @@ -219,17 +227,21 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) thd->variables.select_limit= HA_POS_ERROR; if (!(defstr= create_string(thd, &deflen, - type, - name, namelen, - params, strlen(params), - returns, strlen(returns), - body, strlen(body), + type, + name, + params, strlen(params), + returns, strlen(returns), + body, strlen(body), &chistics))) { ret= SP_INTERNAL_ERROR; goto done; } + olddbptr= thd->db; + if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), 1))) + goto done; + { /* This is something of a kludge. We need to initialize some fields * in thd->lex (the unit and master stuff), and the easiest way to @@ -249,6 +261,9 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) LEX *newlex= thd->lex; sp_head *sp= newlex->sphead; + if (olddbptr != thd->db && + (ret= sp_change_db(thd, olddb, 1))) + goto done; if (sp) { if (oldlex != newlex) @@ -260,6 +275,9 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) } else { + if (olddbptr != thd->db && + (ret= sp_change_db(thd, olddb, 1))) + goto done; *sphp= thd->lex->sphead; (*sphp)->set_info((char *)definer, (uint)strlen(definer), created, modified, &chistics); @@ -270,6 +288,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) } done: + if (opened) close_thread_tables(thd); DBUG_RETURN(ret); @@ -302,6 +321,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) ret= SP_GET_FIELD_FAILED; goto done; } + table->field[MYSQL_PROC_FIELD_DB]-> + store(sp->m_db.str, sp->m_db.length, system_charset_info); table->field[MYSQL_PROC_FIELD_NAME]-> store(sp->m_name.str, sp->m_name.length, system_charset_info); table->field[MYSQL_PROC_FIELD_TYPE]-> @@ -342,15 +363,16 @@ done: static int -db_drop_routine(THD *thd, int type, char *name, uint namelen) +db_drop_routine(THD *thd, int type, sp_name *name) { TABLE *table; int ret; bool opened; DBUG_ENTER("db_drop_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name)); + DBUG_PRINT("enter", ("type: %d name: %*s", + type, name->m_name.length, name->m_name.str)); - ret= db_find_routine_aux(thd, type, name, namelen, TL_WRITE, &table, &opened); + ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened); if (ret == SP_OK) { if (table->file->delete_row(table->record[0])) @@ -364,7 +386,7 @@ db_drop_routine(THD *thd, int type, char *name, uint namelen) static int -db_update_routine(THD *thd, int type, char *name, uint namelen, +db_update_routine(THD *thd, int type, sp_name *name, char *newname, uint newnamelen, st_sp_chistics *chistics) { @@ -372,9 +394,10 @@ db_update_routine(THD *thd, int type, char *name, uint namelen, int ret; bool opened; DBUG_ENTER("db_update_routine"); - DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name)); + DBUG_PRINT("enter", ("type: %d name: %*s", + type, name->m_name.length, name->m_name.str)); - ret= db_find_routine_aux(thd, type, name, namelen, TL_WRITE, &table, &opened); + ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened); if (ret == SP_OK) { store_record(table,record[1]); @@ -408,6 +431,7 @@ struct st_used_field static struct st_used_field init_fields[]= { + { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0}, { "Name", NAME_LEN, MYSQL_TYPE_STRING, 0}, { "Type", 9, MYSQL_TYPE_STRING, 0}, { "Definer", 77, MYSQL_TYPE_STRING, 0}, @@ -428,14 +452,20 @@ print_field_values(THD *thd, TABLE *table, if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type) { - String *tmp_string= new String(); + String db_string; + String name_string; struct st_used_field *used_field= used_fields; - get_field(&thd->mem_root, used_field->field, tmp_string); - if (!wild || !wild[0] || !wild_compare(tmp_string->ptr(), wild, 0)) + if (get_field(&thd->mem_root, used_field->field, &db_string)) + db_string.set_ascii("", 0); + used_field+= 1; + get_field(&thd->mem_root, used_field->field, &name_string); + + if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0)) { protocol->prepare_for_resend(); - protocol->store(tmp_string); + protocol->store(&db_string); + protocol->store(&name_string); for (used_field++; used_field->field_name; used_field++) @@ -452,10 +482,10 @@ print_field_values(THD *thd, TABLE *table, break; default: { - String *tmp_string1= new String(); + String tmp_string; - get_field(&thd->mem_root, used_field->field, tmp_string1); - protocol->store(tmp_string1); + get_field(&thd->mem_root, used_field->field, &tmp_string); + protocol->store(&tmp_string); } break; } @@ -563,16 +593,17 @@ done: ******************************************************************************/ sp_head * -sp_find_procedure(THD *thd, LEX_STRING *name) +sp_find_procedure(THD *thd, sp_name *name) { sp_head *sp; DBUG_ENTER("sp_find_procedure"); - DBUG_PRINT("enter", ("name: %*s", name->length, name->str)); + DBUG_PRINT("enter", ("name: %*s.%*s", + name->m_db.length, name->m_db.str, + name->m_name.length, name->m_name.str)); - if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name->str, name->length))) + if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name))) { - if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, - name->str, name->length, &sp) == SP_OK) + if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK) sp_cache_insert(&thd->sp_proc_cache, sp); } @@ -593,40 +624,40 @@ sp_create_procedure(THD *thd, sp_head *sp) int -sp_drop_procedure(THD *thd, char *name, uint namelen) +sp_drop_procedure(THD *thd, sp_name *name) { int ret; DBUG_ENTER("sp_drop_procedure"); - DBUG_PRINT("enter", ("name: %*s", namelen, name)); + DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - sp_cache_remove(&thd->sp_proc_cache, name, namelen); - ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen); + sp_cache_remove(&thd->sp_proc_cache, name); + ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name); DBUG_RETURN(ret); } int -sp_update_procedure(THD *thd, char *name, uint namelen, +sp_update_procedure(THD *thd, sp_name *name, char *newname, uint newnamelen, st_sp_chistics *chistics) { int ret; DBUG_ENTER("sp_update_procedure"); - DBUG_PRINT("enter", ("name: %*s", namelen, name)); + DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - sp_cache_remove(&thd->sp_proc_cache, name, namelen); - ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, + sp_cache_remove(&thd->sp_proc_cache, name); + ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, newname, newnamelen, chistics); DBUG_RETURN(ret); } int -sp_show_create_procedure(THD *thd, LEX_STRING *name) +sp_show_create_procedure(THD *thd, sp_name *name) { sp_head *sp; DBUG_ENTER("sp_show_create_procedure"); - DBUG_PRINT("enter", ("name: %*s", name->length, name->str)); + DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); if ((sp= sp_find_procedure(thd, name))) { @@ -655,16 +686,15 @@ sp_show_status_procedure(THD *thd, const char *wild) ******************************************************************************/ sp_head * -sp_find_function(THD *thd, LEX_STRING *name) +sp_find_function(THD *thd, sp_name *name) { sp_head *sp; DBUG_ENTER("sp_find_function"); - DBUG_PRINT("enter", ("name: %*s", name->length, name->str)); + DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name->str, name->length))) + if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name))) { - if (db_find_routine(thd, TYPE_ENUM_FUNCTION, - name->str, name->length, &sp) != SP_OK) + if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK) sp= NULL; else sp_cache_insert(&thd->sp_func_cache, sp); @@ -686,40 +716,40 @@ sp_create_function(THD *thd, sp_head *sp) int -sp_drop_function(THD *thd, char *name, uint namelen) +sp_drop_function(THD *thd, sp_name *name) { int ret; DBUG_ENTER("sp_drop_function"); - DBUG_PRINT("enter", ("name: %*s", namelen, name)); + DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - sp_cache_remove(&thd->sp_func_cache, name, namelen); - ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen); + sp_cache_remove(&thd->sp_func_cache, name); + ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name); DBUG_RETURN(ret); } int -sp_update_function(THD *thd, char *name, uint namelen, +sp_update_function(THD *thd, sp_name *name, char *newname, uint newnamelen, st_sp_chistics *chistics) { int ret; DBUG_ENTER("sp_update_procedure"); - DBUG_PRINT("enter", ("name: %*s", namelen, name)); + DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - sp_cache_remove(&thd->sp_func_cache, name, namelen); - ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, + sp_cache_remove(&thd->sp_func_cache, name); + ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, newname, newnamelen, chistics); DBUG_RETURN(ret); } int -sp_show_create_function(THD *thd, LEX_STRING *name) +sp_show_create_function(THD *thd, sp_name *name) { sp_head *sp; DBUG_ENTER("sp_show_create_function"); - DBUG_PRINT("enter", ("name: %*s", name->length, name->str)); + DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); if ((sp= sp_find_function(thd, name))) { @@ -741,18 +771,17 @@ sp_show_status_function(THD *thd, const char *wild) } -// QQ Temporary until the function call detection in sql_lex has been reworked. bool -sp_function_exists(THD *thd, LEX_STRING *name) +sp_function_exists(THD *thd, sp_name *name) { TABLE *table; bool ret= FALSE; bool opened= FALSE; DBUG_ENTER("sp_function_exists"); - if (sp_cache_lookup(&thd->sp_func_cache, name->str, name->length) || + if (sp_cache_lookup(&thd->sp_func_cache, name) || db_find_routine_aux(thd, TYPE_ENUM_FUNCTION, - name->str, name->length, TL_READ, + name, TL_READ, &table, &opened) == SP_OK) ret= TRUE; if (opened) @@ -771,13 +800,14 @@ sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first) void -sp_add_fun_to_lex(LEX *lex, LEX_STRING fun) +sp_add_fun_to_lex(LEX *lex, sp_name *fun) { - if (! hash_search(&lex->spfuns, (byte *)fun.str, fun.length)) + if (! hash_search(&lex->spfuns, + (byte *)fun->m_qname.str, fun->m_qname.length)) { LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING)); - ls->str= sql_strmake(fun.str, fun.length); - ls->length= fun.length; + ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length); + ls->length= fun->m_qname.length; my_hash_insert(&lex->spfuns, (byte *)ls); } @@ -806,15 +836,25 @@ sp_cache_functions(THD *thd, LEX *lex) for (uint i=0 ; i < h->records ; i++) { LEX_STRING *ls= (LEX_STRING *)hash_element(h, i); + sp_name name(*ls); - if (! sp_cache_lookup(&thd->sp_func_cache, ls->str, ls->length)) + name.m_qname= *ls; + if (! sp_cache_lookup(&thd->sp_func_cache, &name)) { sp_head *sp; LEX *oldlex= thd->lex; LEX *newlex= new st_lex; thd->lex= newlex; - if (db_find_routine(thd, TYPE_ENUM_FUNCTION, ls->str, ls->length, &sp) == SP_OK) + name.m_name.str= strchr(name.m_qname.str, '.'); + name.m_db.length= name.m_name.str - name.m_qname.str; + name.m_db.str= strmake_root(&thd->mem_root, + name.m_qname.str, name.m_db.length); + name.m_name.str+= 1; + name.m_name.length= name.m_qname.length - name.m_db.length - 1; + + if (db_find_routine(thd, TYPE_ENUM_FUNCTION, &name, &sp) + == SP_OK) { ret= sp_cache_functions(thd, newlex); delete newlex; @@ -840,7 +880,7 @@ sp_cache_functions(THD *thd, LEX *lex) static char * create_string(THD *thd, ulong *lenp, int type, - char *name, ulong namelen, + sp_name *name, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, @@ -849,12 +889,15 @@ create_string(THD *thd, ulong *lenp, char *buf, *ptr; ulong buflen; - buflen= 100 + namelen + paramslen + returnslen + bodylen + chistics->comment.length; + buflen= 100 + name->m_qname.length + paramslen + returnslen + bodylen + + chistics->comment.length; if (!(buf= thd->alloc(buflen))) return 0; - ptr= strxmov(buf, "CREATE ", (type == TYPE_ENUM_FUNCTION) ? "FUNCTION" : "PROCEDURE", - " `", name, "`(", params, ")", NullS); + ptr= strxmov(buf, "CREATE ", + (type == TYPE_ENUM_FUNCTION) ? "FUNCTION" : "PROCEDURE", + " `", name->m_db.str, "`.`", name->m_name.str, "`(", params, ")", + NullS); if (type == TYPE_ENUM_FUNCTION) ptr= strxmov(ptr, " RETURNS ", returns, NullS); @@ -873,3 +916,63 @@ create_string(THD *thd, ulong *lenp, *lenp= (ptr-buf); return buf; } + + +// +// Utilities... +// + +int +sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen, + bool no_access_check) +{ + bool changeit; + DBUG_ENTER("sp_use_new_db"); + DBUG_PRINT("enter", ("newdb: %s", newdb)); + + if (thd->db && thd->db[0]) + { + if (my_strcasecmp(system_charset_info, thd->db, newdb) == 0) + changeit= 0; + else + { + changeit= 1; + strnmov(olddb, thd->db, olddblen); + } + } + else + { // thd->db empty + if (newdb[0]) + changeit= 1; + else + changeit= 0; + olddb[0] = '\0'; + } + if (!changeit) + { + DBUG_RETURN(0); + } + else + { + int ret= sp_change_db(thd, newdb, no_access_check); + + DBUG_RETURN(ret); + } +} + +int +sp_change_db(THD *thd, char *db, bool no_access_check) +{ + int ret; + ulong dbaccess= thd->db_access; /* mysql_change_db() changes this */ + my_bool nsok= thd->net.no_send_ok; /* mysql_change_db() does send_ok() */ + thd->net.no_send_ok= TRUE; + DBUG_ENTER("sp_change_db"); + DBUG_PRINT("enter", ("db: %s, no_access_check: %d", db, no_access_check)); + + ret= mysql_change_db(thd, db, 1, no_access_check); + + thd->net.no_send_ok= nsok; + thd->db_access= dbaccess; + DBUG_RETURN(ret); +} @@ -29,58 +29,72 @@ #define SP_INTERNAL_ERROR -7 sp_head * -sp_find_procedure(THD *thd, LEX_STRING *name); +sp_find_procedure(THD *thd, sp_name *name); int sp_create_procedure(THD *thd, sp_head *sp); int -sp_drop_procedure(THD *thd, char *name, uint namelen); +sp_drop_procedure(THD *thd, sp_name *name); int -sp_update_procedure(THD *thd, char *name, uint namelen, +sp_update_procedure(THD *thd, sp_name *name, char *newname, uint newnamelen, st_sp_chistics *chistics); int -sp_show_create_procedure(THD *thd, LEX_STRING *name); +sp_show_create_procedure(THD *thd, sp_name *name); int sp_show_status_procedure(THD *thd, const char *wild); sp_head * -sp_find_function(THD *thd, LEX_STRING *name); +sp_find_function(THD *thd, sp_name *name); int sp_create_function(THD *thd, sp_head *sp); int -sp_drop_function(THD *thd, char *name, uint namelen); +sp_drop_function(THD *thd, sp_name *name); int -sp_update_function(THD *thd, char *name, uint namelen, +sp_update_function(THD *thd, sp_name *name, char *newname, uint newnamelen, st_sp_chistics *chistics); int -sp_show_create_function(THD *thd, LEX_STRING *name); +sp_show_create_function(THD *thd, sp_name *name); int sp_show_status_function(THD *thd, const char *wild); -// QQ Temporary until the function call detection in sql_lex has been reworked. bool -sp_function_exists(THD *thd, LEX_STRING *name); +sp_function_exists(THD *thd, sp_name *name); // This is needed since we have to read the functions before we // do anything else. void -sp_add_fun_to_lex(LEX *lex, LEX_STRING fun); +sp_add_fun_to_lex(LEX *lex, sp_name *fun); void sp_merge_funs(LEX *dst, LEX *src); int sp_cache_functions(THD *thd, LEX *lex); + +// +// Utilities... +// + +// Do a "use newdb". The current db is stored at olddb. +// If newdb is the same as the current one, nothing is changed. +int +sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax, + bool no_access_check); + +// Like mysql_change_db() but handles empty db name and the send_ok() problem. +int +sp_change_db(THD *thd, char *db, bool no_access_check); + #endif /* _SP_H_ */ diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 657a96ec33d..e13fb2695e7 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -71,7 +71,7 @@ sp_cache_insert(sp_cache **cp, sp_head *sp) } sp_head * -sp_cache_lookup(sp_cache **cp, char *name, uint namelen) +sp_cache_lookup(sp_cache **cp, sp_name *name) { ulong v; sp_cache *c= *cp; @@ -89,11 +89,11 @@ sp_cache_lookup(sp_cache **cp, char *name, uint namelen) c->version= v; return NULL; } - return c->lookup(name, namelen); + return c->lookup(name->m_qname.str, name->m_qname.length); } bool -sp_cache_remove(sp_cache **cp, char *name, uint namelen) +sp_cache_remove(sp_cache **cp, sp_name *name) { sp_cache *c= *cp; bool found= FALSE; @@ -109,7 +109,7 @@ sp_cache_remove(sp_cache **cp, char *name, uint namelen) if (c->version < v) c->remove_all(); else - found= c->remove(name, namelen); + found= c->remove(name->m_qname.str, name->m_qname.length); c->version= v+1; } return found; @@ -120,7 +120,10 @@ static byte * hash_get_key_for_sp_head(const byte *ptr, uint *plen, my_bool first) { - return (byte*) ((sp_head*)ptr)->name(plen); + sp_head *sp= (sp_head *)ptr; + + *plen= sp->m_qname.length; + return (byte*) sp->m_qname.str; } static void diff --git a/sql/sp_cache.h b/sql/sp_cache.h index da25227303b..253e9b11588 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -35,10 +35,10 @@ void sp_cache_clear(sp_cache **cp); void sp_cache_insert(sp_cache **cp, sp_head *sp); /* Lookup an SP in cache */ -sp_head *sp_cache_lookup(sp_cache **cp, char *name, uint namelen); +sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); /* Remove an SP from cache. Returns true if something was removed */ -bool sp_cache_remove(sp_cache **cp, char *name, uint namelen); +bool sp_cache_remove(sp_cache **cp, sp_name *name); /* diff --git a/sql/sp_head.cc b/sql/sp_head.cc index bfd7ad259f6..ebf74e25bbe 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -130,6 +130,52 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) DBUG_RETURN(it); } + +/* + * + * sp_name + * + */ + +void +sp_name::init_qname(THD *thd) +{ + m_qname.length= m_db.length+m_name.length+1; + m_qname.str= alloc_root(&thd->mem_root, m_qname.length+1); + sprintf(m_qname.str, "%*s.%*s", + m_db.length, (m_db.length ? m_db.str : ""), + m_name.length, m_name.str); +} + +sp_name * +sp_name_current_db_new(THD *thd, LEX_STRING name) +{ + sp_name *qname; + + if (! thd->db) + qname= new sp_name(name); + else + { + LEX_STRING db; + + db.length= strlen(thd->db); + db.str= thd->strmake(thd->db, db.length); + qname= new sp_name(db, name); + } + qname->init_qname(thd); + return qname; +} + + +/* ------------------------------------------------------------------ */ + + +/* + * + * sp_head + * + */ + void * sp_head::operator new(size_t size) { @@ -178,22 +224,42 @@ sp_head::init(LEX *lex) lex->spcont= m_pcont= new sp_pcontext(); my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); m_param_begin= m_param_end= m_returns_begin= m_returns_end= m_body_begin= 0; - m_name.str= m_params.str= m_retstr.str= m_body.str= m_defstr.str= 0; - m_name.length= m_params.length= m_retstr.length= m_body.length= - m_defstr.length= 0; + m_qname.str= m_db.str= m_name.str= m_params.str= m_retstr.str= + m_body.str= m_defstr.str= 0; + m_qname.length= m_db.length= m_name.length= m_params.length= + m_retstr.length= m_body.length= m_defstr.length= 0; DBUG_VOID_RETURN; } void -sp_head::init_strings(THD *thd, LEX *lex, LEX_STRING *name) +sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) { DBUG_ENTER("sp_head::init_strings"); /* During parsing, we must use thd->mem_root */ MEM_ROOT *root= &thd->mem_root; - DBUG_PRINT("info", ("name: %*s", name->length, name->str)); - m_name.length= name->length; - m_name.str= strmake_root(root, name->str, name->length); + DBUG_PRINT("info", ("name: %*.s%*s", + name->m_db.length, name->m_db.str, + name->m_name.length, name->m_name.str)); + /* We have to copy strings to get them into the right memroot */ + if (name->m_db.length == 0) + { + m_db.length= (thd->db ? strlen(thd->db) : 0); + m_db.str= strmake_root(root, (thd->db ? thd->db : ""), m_db.length); + } + else + { + m_db.length= name->m_db.length; + m_db.str= strmake_root(root, name->m_db.str, name->m_db.length); + } + m_name.length= name->m_name.length; + m_name.str= strmake_root(root, name->m_name.str, name->m_name.length); + + if (name->m_qname.length == 0) + name->init_qname(thd); + m_qname.length= name->m_qname.length; + m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length); + m_params.length= m_param_end- m_param_begin; m_params.str= strmake_root(root, (char *)m_param_begin, m_params.length); @@ -271,30 +337,22 @@ int sp_head::execute(THD *thd) { DBUG_ENTER("sp_head::execute"); - char olddbname[128]; - char *olddbptr= thd->db; + char olddb[128]; + char *olddbptr; sp_rcontext *ctx= thd->spcont; int ret= 0; uint ip= 0; #ifndef EMBEDDED_LIBRARY - if (check_stack_overrun(thd, olddbptr)) + if (check_stack_overrun(thd, olddb)) { DBUG_RETURN(-1); } #endif - if (olddbptr) - { - uint i= 0; - char *p= olddbptr; - - /* Fast inline strncpy without padding... */ - while (*p && i < sizeof(olddbname)) - olddbname[i++]= *p++; - if (i == sizeof(olddbname)) - i-= 1; // QQ Error or warning for truncate? - olddbname[i]= '\0'; - } + + olddbptr= thd->db; + if ((ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0))) + goto done; if (ctx) ctx->clear_handler(); @@ -333,18 +391,17 @@ sp_head::execute(THD *thd) } } while (ret == 0 && !thd->killed && !thd->query_error); + done: DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d", ret, thd->killed, thd->query_error)); if (thd->killed || thd->query_error) ret= -1; /* If the DB has changed, the pointer has changed too, but the original thd->db will then have been freed */ - if (olddbptr && olddbptr != thd->db) + if (olddbptr != thd->db) { - /* QQ Maybe we should issue some special error message or warning here, - if this fails?? */ if (! thd->killed) - ret= mysql_change_db(thd, olddbname); + ret= sp_change_db(thd, olddb, 0); } DBUG_RETURN(ret); } @@ -711,6 +768,32 @@ sp_head::set_info(char *definer, uint definerlen, m_chistics->comment.length); } +void +sp_head::reset_thd_mem_root(THD *thd) +{ + m_thd_root= thd->mem_root; + thd->mem_root= m_mem_root; + m_free_list= thd->free_list; // Keep the old list + thd->free_list= NULL; // Start a new one + /* Copy the db, since substatements will point to it */ + m_thd_db= thd->db; + thd->db= strmake_root(&thd->mem_root, thd->db, thd->db_length); + m_thd= thd; +} + +void +sp_head::restore_thd_mem_root(THD *thd) +{ + Item *flist= m_free_list; // The old list + m_free_list= thd->free_list; // Get the new one + thd->free_list= flist; // Restore the old one + thd->db= m_thd_db; // Restore the original db pointer + m_mem_root= thd->mem_root; + thd->mem_root= m_thd_root; + m_thd= NULL; +} + + int sp_head::show_create_procedure(THD *thd) { @@ -1092,10 +1175,13 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } +/* ------------------------------------------------------------------ */ + // // Security context swapping // + #ifndef NO_EMBEDDED_ACCESS_CHECKS void sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) @@ -1108,8 +1194,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) { ctxp->master_access= thd->master_access; ctxp->db_access= thd->db_access; - ctxp->db= thd->db; - ctxp->db_length= thd->db_length; ctxp->priv_user= thd->priv_user; strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host)); ctxp->user= thd->user; @@ -1125,8 +1209,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ctxp->changed= FALSE; thd->master_access= ctxp->master_access; thd->db_access= ctxp->db_access; - thd->db= ctxp->db; - thd->db_length= ctxp->db_length; thd->priv_user= ctxp->priv_user; strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); } @@ -1146,8 +1228,6 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ctxp->changed= FALSE; thd->master_access= ctxp->master_access; thd->db_access= ctxp->db_access; - thd->db= ctxp->db; - thd->db_length= ctxp->db_length; thd->priv_user= ctxp->priv_user; strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); } diff --git a/sql/sp_head.h b/sql/sp_head.h index b2dee5204bb..791c6697693 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -37,6 +37,39 @@ class sp_instr; struct sp_cond_type; struct sp_pvar; +class sp_name : public Sql_alloc +{ +public: + + LEX_STRING m_db; + LEX_STRING m_name; + LEX_STRING m_qname; + + sp_name(LEX_STRING name) + : m_name(name) + { + m_db.str= m_qname.str= 0; + m_db.length= m_qname.length= 0; + } + + sp_name(LEX_STRING db, LEX_STRING name) + : m_db(db), m_name(name) + { + m_qname.str= 0; + m_qname.length= 0; + } + + // Init. the qualified name from the db and name. + void init_qname(THD *thd); // thd for memroot allocation + + ~sp_name() + {} +}; + +sp_name * +sp_name_current_db_new(THD *thd, LEX_STRING name); + + class sp_head : public Sql_alloc { sp_head(const sp_head &); /* Prevent use of these */ @@ -56,6 +89,8 @@ public: List<char *> m_calls; // Called procedures. List<char *> m_tables; // Used tables. #endif + LEX_STRING m_qname; // db.name + LEX_STRING m_db; LEX_STRING m_name; LEX_STRING m_params; LEX_STRING m_retstr; // For FUNCTIONs only @@ -83,7 +118,7 @@ public: // Initialize strings after parsing header void - init_strings(THD *thd, LEX *lex, LEX_STRING *name); + init_strings(THD *thd, LEX *lex, sp_name *name); int create(THD *thd); @@ -163,24 +198,10 @@ public: longlong created, longlong modified, st_sp_chistics *chistics); - inline void reset_thd_mem_root(THD *thd) - { - m_thd_root= thd->mem_root; - thd->mem_root= m_mem_root; - m_free_list= thd->free_list; // Keep the old list - thd->free_list= NULL; // Start a new one - m_thd= thd; - } + void reset_thd_mem_root(THD *thd); + + void restore_thd_mem_root(THD *thd); - inline void restore_thd_mem_root(THD *thd) - { - Item *flist= m_free_list; // The old list - m_free_list= thd->free_list; // Get the new one - thd->free_list= flist; // Restore the old one - m_mem_root= thd->mem_root; - thd->mem_root= m_thd_root; - m_thd= NULL; - } private: @@ -188,6 +209,7 @@ private: MEM_ROOT m_thd_root; // Temp. store for thd's mem_root Item *m_free_list; // Where the items go THD *m_thd; // Set if we have reset mem_root + char *m_thd_db; // Original thd->db pointer sp_pcontext *m_pcont; // Parse context List<LEX> m_lex; // Temp. store for the other lex @@ -640,8 +662,6 @@ struct st_sp_security_context bool changed; uint master_access; uint db_access; - char *db; - uint db_length; char *priv_user; char priv_host[MAX_HOSTNAME]; char *user; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index bc6b30040d6..3ea6821ef80 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -595,7 +595,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, 1 error */ -bool mysql_change_db(THD *thd, const char *name) +bool mysql_change_db(THD *thd, const char *name, + bool empty_is_ok, bool no_access_check) { int length, db_length; char *dbname=my_strdup((char*) name,MYF(MY_WME)); @@ -604,62 +605,76 @@ bool mysql_change_db(THD *thd, const char *name) HA_CREATE_INFO create; DBUG_ENTER("mysql_change_db"); - if (!dbname || !(db_length=strip_sp(dbname))) + if ((!dbname || !(db_length=strip_sp(dbname))) && !empty_is_ok) { x_free(dbname); /* purecov: inspected */ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } - if ((db_length > NAME_LEN) || check_db_name(dbname)) + if (!empty_is_ok || (dbname && db_length)) { - net_printf(thd, ER_WRONG_DB_NAME, dbname); - x_free(dbname); - DBUG_RETURN(1); + if ((db_length > NAME_LEN) || check_db_name(dbname)) + { + net_printf(thd, ER_WRONG_DB_NAME, dbname); + x_free(dbname); + DBUG_RETURN(1); + } } DBUG_PRINT("info",("Use database: %s", dbname)); -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (test_all_bits(thd->master_access,DB_ACLS)) - db_access=DB_ACLS; - else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); - if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) + if (!empty_is_ok || (dbname && db_length)) { - net_printf(thd,ER_DBACCESS_DENIED_ERROR, - thd->priv_user, - thd->priv_host, - dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, - thd->priv_host, - dbname); - my_free(dbname,MYF(0)); - DBUG_RETURN(1); - } +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (! no_access_check) + { + if (test_all_bits(thd->master_access,DB_ACLS)) + db_access=DB_ACLS; + else + db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | + thd->master_access); + if (!(db_access & DB_ACLS) && + (!grant_option || check_grant_db(thd,dbname))) + { + net_printf(thd,ER_DBACCESS_DENIED_ERROR, + thd->priv_user, + thd->priv_host, + dbname); + mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), + thd->priv_user, + thd->priv_host, + dbname); + my_free(dbname,MYF(0)); + DBUG_RETURN(1); + } + } #endif - (void) sprintf(path,"%s/%s",mysql_data_home,dbname); - length=unpack_dirname(path,path); // Convert if not unix - if (length && path[length-1] == FN_LIBCHAR) - path[length-1]=0; // remove ending '\' - if (access(path,F_OK)) - { - net_printf(thd,ER_BAD_DB_ERROR,dbname); - my_free(dbname,MYF(0)); - DBUG_RETURN(1); + (void) sprintf(path,"%s/%s",mysql_data_home,dbname); + length=unpack_dirname(path,path); // Convert if not unix + if (length && path[length-1] == FN_LIBCHAR) + path[length-1]=0; // remove ending '\' + if (access(path,F_OK)) + { + net_printf(thd,ER_BAD_DB_ERROR,dbname); + my_free(dbname,MYF(0)); + DBUG_RETURN(1); + } } send_ok(thd); x_free(thd->db); thd->db=dbname; // THD::~THD will free this thd->db_length=db_length; + if (!empty_is_ok || (dbname && db_length)) + { #ifndef NO_EMBEDDED_ACCESS_CHECKS - thd->db_access=db_access; + if (! no_access_check) + thd->db_access=db_access; #endif - strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); - load_db_opt(thd, path, &create); - thd->db_charset= create.default_table_charset ? - create.default_table_charset : - thd->variables.collation_server; - thd->variables.collation_database= thd->db_charset; + strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); + load_db_opt(thd, path, &create); + thd->db_charset= create.default_table_charset ? + create.default_table_charset : + thd->variables.collation_server; + thd->variables.collation_database= thd->db_charset; + } DBUG_RETURN(0); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f37f133f105..6f6a8925412 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -168,38 +168,6 @@ static int find_keyword(LEX *lex, uint len, bool function) lex->yylval->symbol.length=len; return symbol->tok; } - - LEX_STRING ls; - ls.str = (char *)tok; ls.length= len; - if (function && sp_function_exists(current_thd, &ls)) // QQ temp fix - { - lex->safe_to_cache_query= 0; - lex->yylval->lex_str.str= lex->thd->strmake((char*)lex->tok_start, len); - lex->yylval->lex_str.length= len; - return SP_FUNC; - } - -#ifdef HAVE_DLOPEN - udf_func *udf; - if (function && using_udf_functions && (udf=find_udf((char*) tok, len))) - { - lex->safe_to_cache_query=0; - lex->yylval->udf=udf; - switch (udf->returns) { - case STRING_RESULT: - return (udf->type == UDFTYPE_FUNCTION) ? UDF_CHAR_FUNC : UDA_CHAR_SUM; - case REAL_RESULT: - return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM; - case INT_RESULT: - return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - return 0; - } - } -#endif return 0; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 50b8f322731..221f864db81 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -22,6 +22,7 @@ class Table_ident; class sql_exchange; class LEX_COLUMN; class sp_head; +class sp_name; class sp_instr; class sp_pcontext; @@ -604,6 +605,7 @@ typedef struct st_lex bool derived_tables; bool safe_to_cache_query; sp_head *sphead; + sp_name *spname; bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */ sp_pcontext *spcont; HASH spfuns; /* Called functions */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d332b6985cb..273e994189f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3105,9 +3105,9 @@ mysql_execute_command(THD *thd) if (check_access(thd,INSERT_ACL,"mysql",0,1,0)) break; #ifdef HAVE_DLOPEN - if ((sph= sp_find_function(thd, &lex->udf.name))) + if ((sph= sp_find_function(thd, lex->spname))) { - net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str); + net_printf(thd, ER_UDF_EXISTS, lex->spname->m_name.str); goto error; } if (!(res = mysql_create_function(thd,&lex->udf))) @@ -3445,9 +3445,10 @@ mysql_execute_command(THD *thd) { sp_head *sp; - if (!(sp= sp_find_procedure(thd, &lex->udf.name))) + if (!(sp= sp_find_procedure(thd, lex->spname))) { - net_printf(thd, ER_SP_DOES_NOT_EXIST, "PROCEDURE", lex->udf.name); + net_printf(thd, ER_SP_DOES_NOT_EXIST, "PROCEDURE", + lex->spname->m_name.str); goto error; } else @@ -3525,10 +3526,10 @@ mysql_execute_command(THD *thd) goto error; } if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) - res= sp_update_procedure(thd, lex->udf.name.str, lex->udf.name.length, + res= sp_update_procedure(thd, lex->spname, lex->name, newname_len, &lex->sp_chistics); else - res= sp_update_function(thd, lex->udf.name.str, lex->udf.name.length, + res= sp_update_function(thd, lex->spname, lex->name, newname_len, &lex->sp_chistics); switch (res) { @@ -3536,10 +3537,12 @@ mysql_execute_command(THD *thd) send_ok(thd); break; case SP_KEY_NOT_FOUND: - net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),lex->udf.name); + net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex), + lex->spname->m_name.str); goto error; default: - net_printf(thd, ER_SP_CANT_ALTER, SP_COM_STRING(lex),lex->udf.name); + net_printf(thd, ER_SP_CANT_ALTER, SP_COM_STRING(lex), + lex->spname->m_name.str); goto error; } break; @@ -3548,19 +3551,20 @@ mysql_execute_command(THD *thd) case SQLCOM_DROP_FUNCTION: { if (lex->sql_command == SQLCOM_DROP_PROCEDURE) - res= sp_drop_procedure(thd, lex->udf.name.str, lex->udf.name.length); + res= sp_drop_procedure(thd, lex->spname); else { - res= sp_drop_function(thd, lex->udf.name.str, lex->udf.name.length); + res= sp_drop_function(thd, lex->spname); #ifdef HAVE_DLOPEN if (res == SP_KEY_NOT_FOUND) { - udf_func *udf = find_udf(lex->udf.name.str, lex->udf.name.length); + udf_func *udf = find_udf(lex->spname->m_name.str, + lex->spname->m_name.length); if (udf) { if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0)) goto error; - if (!(res = mysql_drop_function(thd,&lex->udf.name))) + if (!(res = mysql_drop_function(thd,&lex->spname->m_name))) { send_ok(thd); break; @@ -3579,17 +3583,17 @@ mysql_execute_command(THD *thd) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), - SP_COM_STRING(lex), lex->udf.name.str); + SP_COM_STRING(lex), lex->spname->m_name.str); res= 0; send_ok(thd); break; } net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex), - lex->udf.name.str); + lex->spname->m_name.str); goto error; default: net_printf(thd, ER_SP_DROP_FAILED, SP_COM_STRING(lex), - lex->udf.name.str); + lex->spname->m_name.str); goto error; } break; @@ -3597,16 +3601,16 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_CREATE_PROC: { res= -1; - if (lex->udf.name.length > NAME_LEN) + if (lex->spname->m_name.length > NAME_LEN) { - net_printf(thd, ER_TOO_LONG_IDENT, lex->udf.name.str); + net_printf(thd, ER_TOO_LONG_IDENT, lex->spname->m_name.str); goto error; } - res= sp_show_create_procedure(thd, &lex->udf.name); + res= sp_show_create_procedure(thd, lex->spname); if (res != SP_OK) { /* We don't distinguish between errors for now */ net_printf(thd, ER_SP_DOES_NOT_EXIST, - SP_COM_STRING(lex), lex->udf.name.str); + SP_COM_STRING(lex), lex->spname->m_name.str); res= 0; goto error; } @@ -3614,16 +3618,16 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_CREATE_FUNC: { - if (lex->udf.name.length > NAME_LEN) + if (lex->spname->m_name.length > NAME_LEN) { - net_printf(thd, ER_TOO_LONG_IDENT, lex->udf.name.str); + net_printf(thd, ER_TOO_LONG_IDENT, lex->spname->m_name.str); goto error; } - res= sp_show_create_function(thd, &lex->udf.name); + res= sp_show_create_function(thd, lex->spname); if (res != SP_OK) { /* We don't distinguish between errors for now */ net_printf(thd, ER_SP_DOES_NOT_EXIST, - SP_COM_STRING(lex), lex->udf.name.str); + SP_COM_STRING(lex), lex->spname->m_name.str); res= 0; goto error; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4c217b325ec..50f475eb68c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -92,6 +92,7 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B) chooser_compare_func_creator boolfunc2creator; struct sp_cond_type *spcondtype; struct { int vars, conds, hndlrs, curs; } spblock; + sp_name *spname; struct st_lex *lex; } @@ -568,17 +569,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SECOND_SYM %token SECOND_MICROSECOND_SYM %token SHARE_SYM -%token SP_FUNC %token SUBDATE_SYM %token SUBSTRING %token SUBSTRING_INDEX %token TRIM -%token UDA_CHAR_SUM -%token UDA_FLOAT_SUM -%token UDA_INT_SUM -%token UDF_CHAR_FUNC -%token UDF_FLOAT_FUNC -%token UDF_INT_FUNC %token UNIQUE_USERS %token UNIX_TIMESTAMP %token USER @@ -640,7 +634,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component key_cache_name - SP_FUNC ident_or_spfunc sp_opt_label + sp_opt_label %type <lex_str_ptr> opt_table_alias @@ -683,7 +677,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); simple_ident_nospvar simple_ident_q %type <item_list> - expr_list sp_expr_list udf_expr_list udf_expr_list2 when_list + expr_list udf_expr_list udf_expr_list2 when_list ident_list ident_list_arg %type <key_type> @@ -701,10 +695,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %type <table_list> join_table_list join_table -%type <udf> - UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC - UDA_CHAR_SUM UDA_FLOAT_SUM UDA_INT_SUM - %type <date_time_type> date_time_type; %type <interval> interval @@ -782,6 +772,7 @@ END_OF_INPUT %type <spcondtype> sp_cond sp_hcond %type <spblock> sp_decls sp_decl %type <lex> sp_cursor_stmt +%type <spname> sp_name %type <NONE> '-' '+' '*' '/' '%' '(' ')' @@ -1030,15 +1021,15 @@ create: lex->name=$4.str; lex->create_info.options=$3; } - | CREATE udf_func_type FUNCTION_SYM ident_or_spfunc + | CREATE udf_func_type FUNCTION_SYM sp_name { LEX *lex=Lex; - lex->udf.name = $4; + lex->spname= $4; lex->udf.type= $2; } create_function_tail {} - | CREATE PROCEDURE ident + | CREATE PROCEDURE sp_name { LEX *lex= Lex; sp_head *sp; @@ -1089,7 +1080,7 @@ create: { LEX *lex= Lex; - lex->sphead->init_strings(YYTHD, lex, &$3); + lex->sphead->init_strings(YYTHD, lex, $3); lex->sql_command= SQLCOM_CREATE_PROCEDURE; /* Restore flag if it was cleared above */ if (lex->sphead->m_old_cmq) @@ -1098,9 +1089,16 @@ create: } ; -ident_or_spfunc: - IDENT_sys { $$= $1; } - | SP_FUNC { $$= $1; } +sp_name: + IDENT_sys '.' IDENT_sys + { + $$= new sp_name($1, $3); + $$->init_qname(YYTHD); + } + | IDENT_sys + { + $$= sp_name_current_db_new(YYTHD, $1); + } ; create_function_tail: @@ -1108,6 +1106,7 @@ create_function_tail: { LEX *lex=Lex; lex->sql_command = SQLCOM_CREATE_FUNCTION; + lex->udf.name = lex->spname->m_name; lex->udf.returns=(Item_result) $2; lex->udf.dl=$4.str; } @@ -1169,7 +1168,7 @@ create_function_tail: sp_head *sp= lex->sphead; lex->sql_command= SQLCOM_CREATE_SPFUNCTION; - sp->init_strings(YYTHD, lex, &lex->udf.name); + sp->init_strings(YYTHD, lex, lex->spname); /* Restore flag if it was cleared above */ if (sp->m_old_cmq) YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; @@ -1219,12 +1218,12 @@ sp_suid: ; call: - CALL_SYM ident_or_spfunc + CALL_SYM sp_name { LEX *lex = Lex; lex->sql_command= SQLCOM_CALL; - lex->udf.name= $2; + lex->spname= $2; lex->value_list.empty(); } '(' sp_cparam_list ')' {} @@ -1584,6 +1583,11 @@ sp_proc_stmt: /* We maybe have one or more SELECT without INTO */ lex->sphead->m_multi_results= TRUE; } + if (lex->sql_command == SQLCOM_CHANGE_DB) + { /* "USE db" doesn't work in a procedure */ + send_error(YYTHD, ER_SP_NO_USE); + YYABORT; + } /* Don't add an instruction for empty SET statements. ** (This happens if the SET only contained local variables, ** which get their set instructions generated separately.) @@ -2739,7 +2743,7 @@ alter: lex->sql_command=SQLCOM_ALTER_DB; lex->name=$3.str; } - | ALTER PROCEDURE ident + | ALTER PROCEDURE sp_name { LEX *lex= Lex; @@ -2752,9 +2756,9 @@ alter: LEX *lex=Lex; lex->sql_command= SQLCOM_ALTER_PROCEDURE; - lex->udf.name= $3; + lex->spname= $3; } - | ALTER FUNCTION_SYM ident + | ALTER FUNCTION_SYM sp_name { LEX *lex= Lex; @@ -2767,7 +2771,7 @@ alter: LEX *lex=Lex; lex->sql_command= SQLCOM_ALTER_FUNCTION; - lex->udf.name= $3; + lex->spname= $3; } ; @@ -3919,55 +3923,82 @@ simple_expr: { $$= new Item_func_round($3,$5,1); } | TRUE_SYM { $$= new Item_int((char*) "TRUE",1,1); } - | SP_FUNC '(' sp_expr_list ')' - { - sp_add_fun_to_lex(Lex, $1); - if ($3) - $$= new Item_func_sp($1, *$3); - else - $$= new Item_func_sp($1); - } - | UDA_CHAR_SUM '(' udf_expr_list ')' - { - if ($3 != NULL) - $$ = new Item_sum_udf_str($1, *$3); - else - $$ = new Item_sum_udf_str($1); - } - | UDA_FLOAT_SUM '(' udf_expr_list ')' - { - if ($3 != NULL) - $$ = new Item_sum_udf_float($1, *$3); - else - $$ = new Item_sum_udf_float($1); - } - | UDA_INT_SUM '(' udf_expr_list ')' - { - if ($3 != NULL) - $$ = new Item_sum_udf_int($1, *$3); - else - $$ = new Item_sum_udf_int($1); - } - | UDF_CHAR_FUNC '(' udf_expr_list ')' - { - if ($3 != NULL) - $$ = new Item_func_udf_str($1, *$3); - else - $$ = new Item_func_udf_str($1); - } - | UDF_FLOAT_FUNC '(' udf_expr_list ')' + | IDENT_sys '(' udf_expr_list ')' { - if ($3 != NULL) - $$ = new Item_func_udf_float($1, *$3); - else - $$ = new Item_func_udf_float($1); - } - | UDF_INT_FUNC '(' udf_expr_list ')' - { - if ($3 != NULL) - $$ = new Item_func_udf_int($1, *$3); + sp_name *name= sp_name_current_db_new(YYTHD, $1); + + if (sp_function_exists(YYTHD, name)) + { + LEX *lex= Lex; + + sp_add_fun_to_lex(lex, name); + if ($3) + $$= new Item_func_sp(name, *$3); + else + $$= new Item_func_sp(name); + } else - $$ = new Item_func_udf_int($1); + { +#ifdef HAVE_DLOPEN + udf_func *udf; + + if (using_udf_functions && (udf=find_udf($1.str, $1.length))) + { + switch (udf->returns) { + case STRING_RESULT: + if (udf->type == UDFTYPE_FUNCTION) + { + if ($3 != NULL) + $$ = new Item_func_udf_str(udf, *$3); + else + $$ = new Item_func_udf_str(udf); + } + else + { + if ($3 != NULL) + $$ = new Item_sum_udf_str(udf, *$3); + else + $$ = new Item_sum_udf_str(udf); + } + break; + case REAL_RESULT: + if (udf->type == UDFTYPE_FUNCTION) + { + if ($3 != NULL) + $$ = new Item_func_udf_float(udf, *$3); + else + $$ = new Item_func_udf_float(udf); + } + else + { + if ($3 != NULL) + $$ = new Item_sum_udf_float(udf, *$3); + else + $$ = new Item_sum_udf_float(udf); + } + break; + case INT_RESULT: + if (udf->type == UDFTYPE_FUNCTION) + { + if ($3 != NULL) + $$ = new Item_func_udf_int(udf, *$3); + else + $$ = new Item_func_udf_int(udf); + } + else + { + if ($3 != NULL) + $$ = new Item_sum_udf_int(udf, *$3); + else + $$ = new Item_sum_udf_int(udf); + } + break; + default: + YYABORT; + } + } +#endif /* HAVE_DLOPEN */ + } } | UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')' { @@ -4075,10 +4106,6 @@ fulltext_options: | IN_SYM BOOLEAN_SYM MODE_SYM { $$= FT_BOOL; } ; -sp_expr_list: - /* empty */ { $$= NULL; } - | expr_list { $$= $1;}; - udf_expr_list: /* empty */ { $$= NULL; } | udf_expr_list2 { $$= $1;} @@ -4825,19 +4852,19 @@ drop: lex->drop_if_exists=$3; lex->name=$4.str; } - | DROP FUNCTION_SYM if_exists IDENT_sys opt_restrict + | DROP FUNCTION_SYM if_exists sp_name opt_restrict { LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_FUNCTION; lex->drop_if_exists= $3; - lex->udf.name= $4; + lex->spname= $4; } - | DROP PROCEDURE if_exists IDENT_sys opt_restrict + | DROP PROCEDURE if_exists sp_name opt_restrict { LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_PROCEDURE; lex->drop_if_exists= $3; - lex->udf.name= $4; + lex->spname= $4; } | DROP USER { @@ -5316,15 +5343,19 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; } - | CREATE PROCEDURE ident + | CREATE PROCEDURE sp_name { - Lex->sql_command = SQLCOM_SHOW_CREATE_PROC; - Lex->udf.name= $3; + LEX *lex= Lex; + + lex->sql_command = SQLCOM_SHOW_CREATE_PROC; + lex->spname= $3; } - | CREATE FUNCTION_SYM ident + | CREATE FUNCTION_SYM sp_name { - Lex->sql_command = SQLCOM_SHOW_CREATE_FUNC; - Lex->udf.name= $3; + LEX *lex= Lex; + + lex->sql_command = SQLCOM_SHOW_CREATE_FUNC; + lex->spname= $3; } | PROCEDURE STATUS_SYM wild { |