Commit eb4aa092 authored by unknown's avatar unknown

WL#1366: Use the schema (db) associated with an SP.

Phase 2: Make SPs belong to a DB, and use qualified names.
  As a side effect, using USE in an SP is no longer allowed.
  (It just doesn't work otherwise.)


include/mysqld_error.h:
  New error code (USE is no longer allowed in a stored procedure).
include/sql_state.h:
  New error state (USE is no longer allowed in a stored procedure).
mysql-test/r/sp-error.result:
  Updated result for test of USE in SP (not allowed now).
mysql-test/r/sp-security.result:
  Updated test results for new db column and qualified procedured names.
mysql-test/r/sp.result:
  Updated results for USE in SP (as it's no longer allowed), and
  for new db column in status result.
mysql-test/t/sp-error.test:
  Moved test of USE in SP from sp.test (as it's no longer allowed).
mysql-test/t/sp-security.test:
  Ajusted tests for new db column and qualified procedured names.
mysql-test/t/sp.test:
  Moved test of USE in SP to sp-error.test (as it's no longer allowed).
  Adjusted tests for new db column in status result.
sql/mysql_priv.h:
  mysql_change_db() now has optional arguments for use by SP with qualified names.
sql/share/czech/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/danish/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/dutch/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/english/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/estonian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/french/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/german/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/greek/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/hungarian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/italian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/japanese/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/korean/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/norwegian-ny/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/norwegian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/polish/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/portuguese/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/romanian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/russian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/serbian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/slovak/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/spanish/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/swedish/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/share/ukrainian/errmsg.txt:
  New error message: USE is not allowed in a stored procedure.
sql/sp.cc:
  SPs are now "belong" to a DB and may have qualified names.
  New functions for changing DB ("use") when parsing and invoking SPs.
sql/sp.h:
  New functions for changing DB ("use") when parsing and invoking SPs.
sql/sp_cache.cc:
  Use the qualified name in the SP cache.
sql/sp_head.cc:
  New function for allocating a qualified SP name (used in sql_yacc.yy).
  Change DB when executing an SP (if needed).
  Moved thd_mem_root swap functions from sp_head.h.
sql/sp_head.h:
  New function for allocating a qualified SP name (used in sql_yacc.yy).
  Moved thd_mem_root swap functions to sp_head.cc.
sql/sql_db.cc:
  mysql_change_db() now has optional arguments for use by SP with qualified names
  (for use when reading an SP from database and executing it); also allow "unusing"
  a database, i.e. setting thd->thd to "".
sql/sql_yacc.yy:
  Initialize qualfied SP names correctly.
  USE is no longer allowed in an SP.
parent 5aa57221
...@@ -339,4 +339,5 @@ ...@@ -339,4 +339,5 @@
#define ER_SP_DUP_CURS 1320 #define ER_SP_DUP_CURS 1320
#define ER_SP_CANT_ALTER 1321 #define ER_SP_CANT_ALTER 1321
#define ER_SP_SUBSELECT_NYI 1322 #define ER_SP_SUBSELECT_NYI 1322
#define ER_ERROR_MESSAGES 323 #define ER_SP_NO_USE 1323
#define ER_ERROR_MESSAGES 324
...@@ -196,3 +196,4 @@ ER_SP_DUP_COND, "42000", "", ...@@ -196,3 +196,4 @@ ER_SP_DUP_COND, "42000", "",
ER_SP_DUP_CURS, "42000", "", ER_SP_DUP_CURS, "42000", "",
/*ER_SP_CANT_ALTER*/ /*ER_SP_CANT_ALTER*/
ER_SP_SUBSELECT_NYI, "0A000", "", ER_SP_SUBSELECT_NYI, "0A000", "",
ER_SP_NO_USE, "42000", "",
...@@ -251,6 +251,10 @@ declare c cursor for select * from t1; ...@@ -251,6 +251,10 @@ declare c cursor for select * from t1;
declare c cursor for select field from t1; declare c cursor for select field from t1;
end| end|
ERROR 42000: Duplicate cursor: c ERROR 42000: Duplicate cursor: c
create procedure u()
use sptmp;
#|
ERROR 42000: USE is not allowed in a stored procedure
create procedure bug1965() create procedure bug1965()
begin begin
declare c cursor for select val from t1 order by valname; declare c cursor for select val from t1 order by valname;
......
...@@ -8,16 +8,16 @@ create table t1 ( u varchar(64), i int ); ...@@ -8,16 +8,16 @@ create table t1 ( u varchar(64), i int );
create procedure stamp(i int) create procedure stamp(i int)
insert into db1_secret.t1 values (user(), i); insert into db1_secret.t1 values (user(), i);
show procedure status like 'stamp'; show procedure status like 'stamp';
Name Type Definer Modified Created Security_type Comment Db 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 db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call stamp(1); call stamp(1);
select * from t1; select * from t1;
u i u i
root@localhost 1 root@localhost 1
call stamp(2); call db1_secret.stamp(2);
select * from db1_secret.t1; select * from db1_secret.t1;
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret' 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; select * from db1_secret.t1;
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret' ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
select * from t1; select * from t1;
...@@ -27,8 +27,8 @@ user1@localhost 2 ...@@ -27,8 +27,8 @@ user1@localhost 2
anon@localhost 3 anon@localhost 3
alter procedure stamp sql security invoker; alter procedure stamp sql security invoker;
show procedure status like 'stamp'; show procedure status like 'stamp';
Name Type Definer Modified Created Security_type Comment Db 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 db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
call stamp(4); call stamp(4);
select * from t1; select * from t1;
u i u i
...@@ -36,9 +36,9 @@ root@localhost 1 ...@@ -36,9 +36,9 @@ root@localhost 1
user1@localhost 2 user1@localhost 2
anon@localhost 3 anon@localhost 3
root@localhost 4 root@localhost 4
call stamp(5); call db1_secret.stamp(5);
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret' 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' ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
drop database if exists db2; drop database if exists db2;
create database db2; create database db2;
...@@ -73,9 +73,9 @@ s1 ...@@ -73,9 +73,9 @@ s1
0 0
2 2
2 2
drop procedure stamp; drop procedure db1_secret.stamp;
drop procedure p; drop procedure db2.p;
drop procedure q; drop procedure db2.q;
use test; use test;
drop database db1_secret; drop database db1_secret;
drop database db2; drop database db2;
......
...@@ -18,17 +18,6 @@ id data ...@@ -18,17 +18,6 @@ id data
foo 42 foo 42
delete from t1; delete from t1;
drop procedure foo42; 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) create procedure bar(x char(16), y int)
insert into test.t1 values (x, y); insert into test.t1 values (x, y);
call bar("bar", 666); call bar("bar", 666);
...@@ -746,7 +735,7 @@ delete from t1| ...@@ -746,7 +735,7 @@ delete from t1|
alter procedure chistics sql security invoker name chistics2| alter procedure chistics sql security invoker name chistics2|
show create procedure chistics2| show create procedure chistics2|
Procedure Create Procedure Procedure Create Procedure
chistics2 CREATE PROCEDURE `chistics2`() chistics2 CREATE PROCEDURE `test`.`chistics2`()
SQL SECURITY INVOKER SQL SECURITY INVOKER
COMMENT 'Characteristics procedure test' COMMENT 'Characteristics procedure test'
insert into t1 values ("chistics", 1) insert into t1 values ("chistics", 1)
...@@ -763,7 +752,7 @@ chistics() ...@@ -763,7 +752,7 @@ chistics()
alter function chistics name chistics2 comment 'Characteristics function test'| alter function chistics name chistics2 comment 'Characteristics function test'|
show create function chistics2| show create function chistics2|
Function Create Function Function Create Function
chistics2 CREATE FUNCTION `chistics2`() RETURNS int chistics2 CREATE FUNCTION `test`.`chistics2`() RETURNS int
DETERMINISTIC DETERMINISTIC
SQL SECURITY INVOKER SQL SECURITY INVOKER
COMMENT 'Characteristics function test' COMMENT 'Characteristics function test'
...@@ -939,23 +928,23 @@ begin ...@@ -939,23 +928,23 @@ begin
show create function fac; show create function fac;
end| end|
call bug2267_1()| call bug2267_1()|
Name Type Definer Modified Created Security_type Comment Db 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 test 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 test 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 test 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 test bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call bug2267_2()| call bug2267_2()|
Name Type Definer Modified Created Security_type Comment Db 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 test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call bug2267_3()| call bug2267_3()|
Procedure Create Procedure Procedure Create Procedure
bug2267_1 CREATE PROCEDURE `bug2267_1`() bug2267_1 CREATE PROCEDURE `test`.`bug2267_1`()
begin begin
show procedure status; show procedure status;
end end
call bug2267_4()| call bug2267_4()|
Function Create Function 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 begin
declare f bigint unsigned default 1; declare f bigint unsigned default 1;
while n > 1 do while n > 1 do
...@@ -1029,12 +1018,12 @@ n f ...@@ -1029,12 +1018,12 @@ n f
20 2432902008176640000 20 2432902008176640000
drop table fac| drop table fac|
show function status like '%f%'| show function status like '%f%'|
Name Type Definer Modified Created Security_type Comment Db 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 test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
drop procedure ifac| drop procedure ifac|
drop function fac| drop function fac|
show function status like '%f%'| 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| drop table if exists primes|
create table primes ( create table primes (
i int unsigned not null primary key, i int unsigned not null primary key,
...@@ -1095,7 +1084,7 @@ end while; ...@@ -1095,7 +1084,7 @@ end while;
end| end|
show create procedure opp| show create procedure opp|
Procedure Create Procedure 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 begin
declare r double; declare r double;
declare b, s bigint unsigned default 0; declare b, s bigint unsigned default 0;
...@@ -1122,9 +1111,9 @@ end if; ...@@ -1122,9 +1111,9 @@ end if;
end loop; end loop;
end end
show procedure status like '%p%'| show procedure status like '%p%'|
Name Type Definer Modified Created Security_type Comment Db 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 test 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 test opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call ip(200)| call ip(200)|
select * from primes where i=45 or i=100 or i=199| select * from primes where i=45 or i=100 or i=199|
i p i p
...@@ -1135,7 +1124,7 @@ drop table primes| ...@@ -1135,7 +1124,7 @@ drop table primes|
drop procedure opp| drop procedure opp|
drop procedure ip| drop procedure ip|
show procedure status like '%p%'| 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| drop table if exists fib|
create table fib ( f bigint unsigned not null )| create table fib ( f bigint unsigned not null )|
insert into fib values (1), (1)| insert into fib values (1), (1)|
...@@ -1185,19 +1174,19 @@ create procedure bar(x char(16), y int) ...@@ -1185,19 +1174,19 @@ create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker comment "111111111111" sql security invoker
insert into test.t1 values (x, y)| insert into test.t1 values (x, y)|
show procedure status like 'bar'| show procedure status like 'bar'|
Name Type Definer Modified Created Security_type Comment Db 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 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 bar name bar2 comment "2222222222" sql security definer|
alter procedure bar2 name bar comment "3333333333"| alter procedure bar2 name bar comment "3333333333"|
alter procedure bar| alter procedure bar|
show create procedure bar| show create procedure bar|
Procedure Create Procedure Procedure Create Procedure
bar CREATE PROCEDURE `bar`(x char(16), y int) bar CREATE PROCEDURE `test`.`bar`(x char(16), y int)
COMMENT '3333333333' COMMENT '3333333333'
insert into test.t1 values (x, y) insert into test.t1 values (x, y)
show procedure status like 'bar'| show procedure status like 'bar'|
Name Type Definer Modified Created Security_type Comment Db 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 test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333
drop procedure bar| drop procedure bar|
drop table t1; drop table t1;
drop table t2; drop table t2;
...@@ -330,6 +330,12 @@ begin ...@@ -330,6 +330,12 @@ begin
declare c cursor for select field from t1; declare c cursor for select field from t1;
end| end|
# USE is not allowed
--error 1323
create procedure u()
use sptmp;
# #
# BUG#1965 # BUG#1965
# #
......
...@@ -24,7 +24,7 @@ create table t1 ( u varchar(64), i int ); ...@@ -24,7 +24,7 @@ create table t1 ( u varchar(64), i int );
# Our test procedure # Our test procedure
create procedure stamp(i int) create procedure stamp(i int)
insert into db1_secret.t1 values (user(), i); 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'; show procedure status like 'stamp';
# root can, of course # root can, of course
...@@ -40,7 +40,7 @@ connect (con3anon,localhost,anon,,); ...@@ -40,7 +40,7 @@ connect (con3anon,localhost,anon,,);
connection con2user1; connection con2user1;
# This should work... # This should work...
call stamp(2); call db1_secret.stamp(2);
# ...but not this # ...but not this
--error 1044 --error 1044
...@@ -52,7 +52,7 @@ select * from db1_secret.t1; ...@@ -52,7 +52,7 @@ select * from db1_secret.t1;
connection con3anon; connection con3anon;
# This should work... # This should work...
call stamp(3); call db1_secret.stamp(3);
# ...but not this # ...but not this
--error 1044 --error 1044
...@@ -68,7 +68,7 @@ select * from t1; ...@@ -68,7 +68,7 @@ select * from t1;
# Change to invoker's rights # Change to invoker's rights
# #
alter procedure stamp sql security invoker; 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'; show procedure status like 'stamp';
# root still can # root still can
...@@ -82,7 +82,7 @@ connection con2user1; ...@@ -82,7 +82,7 @@ connection con2user1;
# This should not work # This should not work
--error 1044 --error 1044
call stamp(5); call db1_secret.stamp(5);
# #
# Anonymous cannot # Anonymous cannot
...@@ -91,7 +91,7 @@ connection con3anon; ...@@ -91,7 +91,7 @@ connection con3anon;
# This should not work # This should not work
--error 1044 --error 1044
call stamp(6); call db1_secret.stamp(6);
# #
...@@ -148,9 +148,9 @@ select * from t2; ...@@ -148,9 +148,9 @@ select * from t2;
# Clean up # Clean up
connection con1root; connection con1root;
drop procedure stamp; drop procedure db1_secret.stamp;
drop procedure p; drop procedure db2.p;
drop procedure q; drop procedure db2.q;
use test; use test;
drop database db1_secret; drop database db1_secret;
drop database db2; drop database db2;
......
...@@ -31,21 +31,6 @@ delete from t1; ...@@ -31,21 +31,6 @@ delete from t1;
drop procedure foo42; 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. # Single statement, two IN params.
create procedure bar(x char(16), y int) create procedure bar(x char(16), y int)
insert into test.t1 values (x, y); insert into test.t1 values (x, y);
...@@ -1094,9 +1079,9 @@ begin ...@@ -1094,9 +1079,9 @@ begin
show create function fac; show create function fac;
end| 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()| 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_2()|
call bug2267_3()| call bug2267_3()|
call bug2267_4()| call bug2267_4()|
...@@ -1168,11 +1153,11 @@ end| ...@@ -1168,11 +1153,11 @@ end|
call ifac(20)| call ifac(20)|
select * from fac| select * from fac|
drop table 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%'| show function status like '%f%'|
drop procedure ifac| drop procedure ifac|
drop function fac| 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%'| show function status like '%f%'|
...@@ -1249,7 +1234,7 @@ begin ...@@ -1249,7 +1234,7 @@ begin
end while; end while;
end| end|
show create procedure opp| 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%'| show procedure status like '%p%'|
# This isn't the fastest way in the world to compute prime numbers, so # This isn't the fastest way in the world to compute prime numbers, so
...@@ -1261,7 +1246,7 @@ select * from primes where i=45 or i=100 or i=199| ...@@ -1261,7 +1246,7 @@ select * from primes where i=45 or i=100 or i=199|
drop table primes| drop table primes|
drop procedure opp| drop procedure opp|
drop procedure ip| 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%'| show procedure status like '%p%'|
...@@ -1308,13 +1293,13 @@ drop procedure fib| ...@@ -1308,13 +1293,13 @@ drop procedure fib|
create procedure bar(x char(16), y int) create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker comment "111111111111" sql security invoker
insert into test.t1 values (x, y)| 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'| show procedure status like 'bar'|
alter procedure bar name bar2 comment "2222222222" sql security definer| alter procedure bar name bar2 comment "2222222222" sql security definer|
alter procedure bar2 name bar comment "3333333333"| alter procedure bar2 name bar comment "3333333333"|
alter procedure bar| alter procedure bar|
show create 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'| show procedure status like 'bar'|
drop procedure bar| drop procedure bar|
delimiter ;| delimiter ;|
......
...@@ -445,7 +445,8 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, ...@@ -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, int quick_rm_table(enum db_type base,const char *db,
const char *table_name); const char *table_name);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); 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); void mysql_parse(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command); bool is_update_query(enum enum_sql_command command);
void free_items(Item *item); void free_items(Item *item);
......
...@@ -335,3 +335,4 @@ character-set=latin2 ...@@ -335,3 +335,4 @@ character-set=latin2
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -329,3 +329,4 @@ character-set=latin1 ...@@ -329,3 +329,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -337,3 +337,4 @@ character-set=latin1 ...@@ -337,3 +337,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -326,3 +326,4 @@ character-set=latin1 ...@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -331,3 +331,4 @@ character-set=latin7 ...@@ -331,3 +331,4 @@ character-set=latin7
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -326,3 +326,4 @@ character-set=latin1 ...@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -338,3 +338,4 @@ character-set=latin1 ...@@ -338,3 +338,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -326,3 +326,4 @@ character-set=greek ...@@ -326,3 +326,4 @@ character-set=greek
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -328,3 +328,4 @@ character-set=latin2 ...@@ -328,3 +328,4 @@ character-set=latin2
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -326,3 +326,4 @@ character-set=latin1 ...@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -328,3 +328,4 @@ character-set=ujis ...@@ -328,3 +328,4 @@ character-set=ujis
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -326,3 +326,4 @@ character-set=euckr ...@@ -326,3 +326,4 @@ character-set=euckr
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -328,3 +328,4 @@ character-set=latin1 ...@@ -328,3 +328,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -328,3 +328,4 @@ character-set=latin1 ...@@ -328,3 +328,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -330,3 +330,4 @@ character-set=latin2 ...@@ -330,3 +330,4 @@ character-set=latin2
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -327,3 +327,4 @@ character-set=latin1 ...@@ -327,3 +327,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -330,3 +330,4 @@ character-set=latin2 ...@@ -330,3 +330,4 @@ character-set=latin2
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -328,3 +328,4 @@ character-set=koi8r ...@@ -328,3 +328,4 @@ character-set=koi8r
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -321,3 +321,4 @@ character-set=cp1250 ...@@ -321,3 +321,4 @@ character-set=cp1250
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -334,3 +334,4 @@ character-set=latin2 ...@@ -334,3 +334,4 @@ character-set=latin2
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -328,3 +328,4 @@ character-set=latin1 ...@@ -328,3 +328,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -326,3 +326,4 @@ character-set=latin1 ...@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -331,3 +331,4 @@ character-set=koi8u ...@@ -331,3 +331,4 @@ character-set=koi8u
"Duplicate cursor: %s" "Duplicate cursor: %s"
"Failed to ALTER %s %s" "Failed to ALTER %s %s"
"Subselect value not supported" "Subselect value not supported"
"USE is not allowed in a stored procedure"
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
static char * static char *
create_string(THD *thd, ulong *lenp, create_string(THD *thd, ulong *lenp,
int sp_type, int sp_type,
char *name, ulong namelen, sp_name *name,
const char *params, ulong paramslen, const char *params, ulong paramslen,
const char *returns, ulong returnslen, const char *returns, ulong returnslen,
const char *body, ulong bodylen, const char *body, ulong bodylen,
...@@ -69,7 +69,11 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, ...@@ -69,7 +69,11 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
type, name->m_name.length, name->m_name.str)); type, name->m_name.length, name->m_name.str));
// Put the key used to read the row together // Put the key used to read the row together
memset(key, (int)' ', 64); // QQ Empty db for now keylen= name->m_db.length;
if (keylen > 64)
keylen= 64;
memcpy(key, name->m_db.str, keylen);
memset(key+keylen, (int)' ', 64-keylen); // Pad with space
keylen= name->m_name.length; keylen= name->m_name.length;
if (keylen > 64) if (keylen > 64)
keylen= 64; keylen= 64;
...@@ -213,6 +217,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) ...@@ -213,6 +217,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
char *defstr; char *defstr;
ulong deflen; ulong deflen;
LEX *oldlex= thd->lex; LEX *oldlex= thd->lex;
char olddb[128];
char *olddbptr;
enum enum_sql_command oldcmd= thd->lex->sql_command; enum enum_sql_command oldcmd= thd->lex->sql_command;
ulong old_sql_mode= thd->variables.sql_mode; ulong old_sql_mode= thd->variables.sql_mode;
ha_rows select_limit= thd->variables.select_limit; ha_rows select_limit= thd->variables.select_limit;
...@@ -221,23 +227,30 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) ...@@ -221,23 +227,30 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
thd->variables.select_limit= HA_POS_ERROR; thd->variables.select_limit= HA_POS_ERROR;
if (!(defstr= create_string(thd, &deflen, if (!(defstr= create_string(thd, &deflen,
type, type,
name->m_name.str, name->m_name.length, name,
params, strlen(params), params, strlen(params),
returns, strlen(returns), returns, strlen(returns),
body, strlen(body), body, strlen(body),
&chistics))) &chistics)))
{ {
ret= SP_INTERNAL_ERROR; ret= SP_INTERNAL_ERROR;
goto done; goto done;
} }
olddbptr= thd->db;
if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), 1)))
goto done;
lex_start(thd, (uchar*)defstr, deflen); lex_start(thd, (uchar*)defstr, deflen);
if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL) if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
{ {
LEX *newlex= thd->lex; LEX *newlex= thd->lex;
sp_head *sp= newlex->sphead; sp_head *sp= newlex->sphead;
if (olddbptr != thd->db &&
(ret= sp_change_db(thd, olddb, 1)))
goto done;
if (sp) if (sp)
{ {
if (oldlex != newlex) if (oldlex != newlex)
...@@ -249,6 +262,9 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) ...@@ -249,6 +262,9 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
} }
else else
{ {
if (olddbptr != thd->db &&
(ret= sp_change_db(thd, olddb, 1)))
goto done;
*sphp= thd->lex->sphead; *sphp= thd->lex->sphead;
(*sphp)->set_info((char *)definer, (uint)strlen(definer), (*sphp)->set_info((char *)definer, (uint)strlen(definer),
created, modified, &chistics); created, modified, &chistics);
...@@ -259,6 +275,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) ...@@ -259,6 +275,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
} }
done: done:
if (opened) if (opened)
close_thread_tables(thd); close_thread_tables(thd);
DBUG_RETURN(ret); DBUG_RETURN(ret);
...@@ -291,9 +308,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) ...@@ -291,9 +308,8 @@ db_create_routine(THD *thd, int type, sp_head *sp)
ret= SP_GET_FIELD_FAILED; ret= SP_GET_FIELD_FAILED;
goto done; goto done;
} }
// QQ Not yet table->field[MYSQL_PROC_FIELD_DB]->
// table->field[MYSQL_PROC_FIELD_DB]-> store(sp->m_db.str, sp->m_db.length, system_charset_info);
// store(sp->m_db.str, sp->m_db.length, system_charset_info);
table->field[MYSQL_PROC_FIELD_NAME]-> table->field[MYSQL_PROC_FIELD_NAME]->
store(sp->m_name.str, sp->m_name.length, system_charset_info); store(sp->m_name.str, sp->m_name.length, system_charset_info);
table->field[MYSQL_PROC_FIELD_TYPE]-> table->field[MYSQL_PROC_FIELD_TYPE]->
...@@ -402,8 +418,7 @@ struct st_used_field ...@@ -402,8 +418,7 @@ struct st_used_field
static struct st_used_field init_fields[]= static struct st_used_field init_fields[]=
{ {
// QQ Not yet { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0},
// { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0},
{ "Name", NAME_LEN, MYSQL_TYPE_STRING, 0}, { "Name", NAME_LEN, MYSQL_TYPE_STRING, 0},
{ "Type", 9, MYSQL_TYPE_STRING, 0}, { "Type", 9, MYSQL_TYPE_STRING, 0},
{ "Definer", 77, MYSQL_TYPE_STRING, 0}, { "Definer", 77, MYSQL_TYPE_STRING, 0},
...@@ -424,14 +439,20 @@ print_field_values(THD *thd, TABLE *table, ...@@ -424,14 +439,20 @@ print_field_values(THD *thd, TABLE *table,
if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type) 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; struct st_used_field *used_field= used_fields;
get_field(&thd->mem_root, used_field->field, tmp_string); if (get_field(&thd->mem_root, used_field->field, &db_string))
if (!wild || !wild[0] || !wild_compare(tmp_string->ptr(), wild, 0)) 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->prepare_for_resend();
protocol->store(tmp_string); protocol->store(&db_string);
protocol->store(&name_string);
for (used_field++; for (used_field++;
used_field->field_name; used_field->field_name;
used_field++) used_field++)
...@@ -448,10 +469,10 @@ print_field_values(THD *thd, TABLE *table, ...@@ -448,10 +469,10 @@ print_field_values(THD *thd, TABLE *table,
break; break;
default: default:
{ {
String *tmp_string1= new String(); String tmp_string;
get_field(&thd->mem_root, used_field->field, tmp_string1); get_field(&thd->mem_root, used_field->field, &tmp_string);
protocol->store(tmp_string1); protocol->store(&tmp_string);
} }
break; break;
} }
...@@ -738,17 +759,16 @@ sp_show_status_function(THD *thd, const char *wild) ...@@ -738,17 +759,16 @@ sp_show_status_function(THD *thd, const char *wild)
bool bool
sp_function_exists(THD *thd, LEX_STRING *name) sp_function_exists(THD *thd, sp_name *name)
{ {
TABLE *table; TABLE *table;
bool ret= FALSE; bool ret= FALSE;
bool opened= FALSE; bool opened= FALSE;
sp_name n(*name);
DBUG_ENTER("sp_function_exists"); DBUG_ENTER("sp_function_exists");
if (sp_cache_lookup(&thd->sp_func_cache, &n) || if (sp_cache_lookup(&thd->sp_func_cache, name) ||
db_find_routine_aux(thd, TYPE_ENUM_FUNCTION, db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
&n, TL_READ, name, TL_READ,
&table, &opened) == SP_OK) &table, &opened) == SP_OK)
ret= TRUE; ret= TRUE;
if (opened) if (opened)
...@@ -770,11 +790,11 @@ void ...@@ -770,11 +790,11 @@ void
sp_add_fun_to_lex(LEX *lex, sp_name *fun) sp_add_fun_to_lex(LEX *lex, sp_name *fun)
{ {
if (! hash_search(&lex->spfuns, if (! hash_search(&lex->spfuns,
(byte *)fun->m_name.str, fun->m_name.length)) (byte *)fun->m_qname.str, fun->m_qname.length))
{ {
LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING)); LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING));
ls->str= sql_strmake(fun->m_name.str, fun->m_name.length); ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length);
ls->length= fun->m_name.length; ls->length= fun->m_qname.length;
my_hash_insert(&lex->spfuns, (byte *)ls); my_hash_insert(&lex->spfuns, (byte *)ls);
} }
...@@ -805,6 +825,7 @@ sp_cache_functions(THD *thd, LEX *lex) ...@@ -805,6 +825,7 @@ sp_cache_functions(THD *thd, LEX *lex)
LEX_STRING *ls= (LEX_STRING *)hash_element(h, i); LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
sp_name name(*ls); sp_name name(*ls);
name.m_qname= *ls;
if (! sp_cache_lookup(&thd->sp_func_cache, &name)) if (! sp_cache_lookup(&thd->sp_func_cache, &name))
{ {
sp_head *sp; sp_head *sp;
...@@ -812,6 +833,13 @@ sp_cache_functions(THD *thd, LEX *lex) ...@@ -812,6 +833,13 @@ sp_cache_functions(THD *thd, LEX *lex)
LEX *newlex= new st_lex; LEX *newlex= new st_lex;
thd->lex= newlex; thd->lex= newlex;
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) if (db_find_routine(thd, TYPE_ENUM_FUNCTION, &name, &sp)
== SP_OK) == SP_OK)
{ {
...@@ -839,7 +867,7 @@ sp_cache_functions(THD *thd, LEX *lex) ...@@ -839,7 +867,7 @@ sp_cache_functions(THD *thd, LEX *lex)
static char * static char *
create_string(THD *thd, ulong *lenp, create_string(THD *thd, ulong *lenp,
int type, int type,
char *name, ulong namelen, sp_name *name,
const char *params, ulong paramslen, const char *params, ulong paramslen,
const char *returns, ulong returnslen, const char *returns, ulong returnslen,
const char *body, ulong bodylen, const char *body, ulong bodylen,
...@@ -848,14 +876,15 @@ create_string(THD *thd, ulong *lenp, ...@@ -848,14 +876,15 @@ create_string(THD *thd, ulong *lenp,
char *buf, *ptr; char *buf, *ptr;
ulong buflen; ulong buflen;
buflen= 100 + namelen + paramslen + returnslen + bodylen + buflen= 100 + name->m_qname.length + paramslen + returnslen + bodylen +
chistics->comment.length; chistics->comment.length;
if (!(buf= thd->alloc(buflen))) if (!(buf= thd->alloc(buflen)))
return 0; return 0;
ptr= strxmov(buf, "CREATE ", ptr= strxmov(buf, "CREATE ",
(type == TYPE_ENUM_FUNCTION) ? "FUNCTION" : "PROCEDURE", (type == TYPE_ENUM_FUNCTION) ? "FUNCTION" : "PROCEDURE",
" `", name, "`(", params, ")", NullS); " `", name->m_db.str, "`.`", name->m_name.str, "`(", params, ")",
NullS);
if (type == TYPE_ENUM_FUNCTION) if (type == TYPE_ENUM_FUNCTION)
ptr= strxmov(ptr, " RETURNS ", returns, NullS); ptr= strxmov(ptr, " RETURNS ", returns, NullS);
...@@ -874,3 +903,63 @@ create_string(THD *thd, ulong *lenp, ...@@ -874,3 +903,63 @@ create_string(THD *thd, ulong *lenp,
*lenp= (ptr-buf); *lenp= (ptr-buf);
return 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);
}
...@@ -70,7 +70,7 @@ int ...@@ -70,7 +70,7 @@ int
sp_show_status_function(THD *thd, const char *wild); sp_show_status_function(THD *thd, const char *wild);
bool 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 // This is needed since we have to read the functions before we
...@@ -82,4 +82,19 @@ sp_merge_funs(LEX *dst, LEX *src); ...@@ -82,4 +82,19 @@ sp_merge_funs(LEX *dst, LEX *src);
int int
sp_cache_functions(THD *thd, LEX *lex); 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_ */ #endif /* _SP_H_ */
...@@ -89,7 +89,7 @@ sp_cache_lookup(sp_cache **cp, sp_name *name) ...@@ -89,7 +89,7 @@ sp_cache_lookup(sp_cache **cp, sp_name *name)
c->version= v; c->version= v;
return NULL; return NULL;
} }
return c->lookup(name->m_name.str, name->m_name.length); return c->lookup(name->m_qname.str, name->m_qname.length);
} }
bool bool
...@@ -109,7 +109,7 @@ sp_cache_remove(sp_cache **cp, sp_name *name) ...@@ -109,7 +109,7 @@ sp_cache_remove(sp_cache **cp, sp_name *name)
if (c->version < v) if (c->version < v)
c->remove_all(); c->remove_all();
else else
found= c->remove(name->m_name.str, name->m_name.length); found= c->remove(name->m_qname.str, name->m_qname.length);
c->version= v+1; c->version= v+1;
} }
return found; return found;
...@@ -120,7 +120,10 @@ static byte * ...@@ -120,7 +120,10 @@ static byte *
hash_get_key_for_sp_head(const byte *ptr, uint *plen, hash_get_key_for_sp_head(const byte *ptr, uint *plen,
my_bool first) 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 static void
......
...@@ -147,6 +147,26 @@ sp_name::init_qname(THD *thd) ...@@ -147,6 +147,26 @@ sp_name::init_qname(THD *thd)
m_name.length, m_name.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;
}
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
...@@ -224,8 +244,8 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) ...@@ -224,8 +244,8 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
/* We have to copy strings to get them into the right memroot */ /* We have to copy strings to get them into the right memroot */
if (name->m_db.length == 0) if (name->m_db.length == 0)
{ {
m_db.length= strlen(thd->db); m_db.length= (thd->db ? strlen(thd->db) : 0);
m_db.str= strmake_root(root, thd->db, m_db.length); m_db.str= strmake_root(root, (thd->db ? thd->db : ""), m_db.length);
} }
else else
{ {
...@@ -317,30 +337,22 @@ int ...@@ -317,30 +337,22 @@ int
sp_head::execute(THD *thd) sp_head::execute(THD *thd)
{ {
DBUG_ENTER("sp_head::execute"); DBUG_ENTER("sp_head::execute");
char olddbname[128]; char olddb[128];
char *olddbptr= thd->db; char *olddbptr;
sp_rcontext *ctx= thd->spcont; sp_rcontext *ctx= thd->spcont;
int ret= 0; int ret= 0;
uint ip= 0; uint ip= 0;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (check_stack_overrun(thd, olddbptr)) if (check_stack_overrun(thd, olddb))
{ {
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
#endif #endif
if (olddbptr)
{ olddbptr= thd->db;
uint i= 0; if ((ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0)))
char *p= olddbptr; goto done;
/* 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';
}
if (ctx) if (ctx)
ctx->clear_handler(); ctx->clear_handler();
...@@ -379,18 +391,17 @@ sp_head::execute(THD *thd) ...@@ -379,18 +391,17 @@ sp_head::execute(THD *thd)
} }
} while (ret == 0 && !thd->killed && !thd->query_error); } while (ret == 0 && !thd->killed && !thd->query_error);
done:
DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d", DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
ret, thd->killed, thd->query_error)); ret, thd->killed, thd->query_error));
if (thd->killed || thd->query_error) if (thd->killed || thd->query_error)
ret= -1; ret= -1;
/* If the DB has changed, the pointer has changed too, but the /* If the DB has changed, the pointer has changed too, but the
original thd->db will then have been freed */ 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) if (! thd->killed)
ret= mysql_change_db(thd, olddbname); ret= sp_change_db(thd, olddb, 0);
} }
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -757,6 +768,32 @@ sp_head::set_info(char *definer, uint definerlen, ...@@ -757,6 +768,32 @@ sp_head::set_info(char *definer, uint definerlen,
m_chistics->comment.length); 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 int
sp_head::show_create_procedure(THD *thd) sp_head::show_create_procedure(THD *thd)
{ {
...@@ -1157,8 +1194,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ...@@ -1157,8 +1194,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
{ {
ctxp->master_access= thd->master_access; ctxp->master_access= thd->master_access;
ctxp->db_access= thd->db_access; ctxp->db_access= thd->db_access;
ctxp->db= thd->db;
ctxp->db_length= thd->db_length;
ctxp->priv_user= thd->priv_user; ctxp->priv_user= thd->priv_user;
strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host)); strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host));
ctxp->user= thd->user; ctxp->user= thd->user;
...@@ -1174,8 +1209,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ...@@ -1174,8 +1209,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
ctxp->changed= FALSE; ctxp->changed= FALSE;
thd->master_access= ctxp->master_access; thd->master_access= ctxp->master_access;
thd->db_access= ctxp->db_access; thd->db_access= ctxp->db_access;
thd->db= ctxp->db;
thd->db_length= ctxp->db_length;
thd->priv_user= ctxp->priv_user; thd->priv_user= ctxp->priv_user;
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
} }
...@@ -1195,8 +1228,6 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ...@@ -1195,8 +1228,6 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
ctxp->changed= FALSE; ctxp->changed= FALSE;
thd->master_access= ctxp->master_access; thd->master_access= ctxp->master_access;
thd->db_access= ctxp->db_access; thd->db_access= ctxp->db_access;
thd->db= ctxp->db;
thd->db_length= ctxp->db_length;
thd->priv_user= ctxp->priv_user; thd->priv_user= ctxp->priv_user;
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host)); strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
} }
......
...@@ -66,6 +66,10 @@ class sp_name : public Sql_alloc ...@@ -66,6 +66,10 @@ class sp_name : public Sql_alloc
{} {}
}; };
sp_name *
sp_name_current_db_new(THD *thd, LEX_STRING name);
class sp_head : public Sql_alloc class sp_head : public Sql_alloc
{ {
sp_head(const sp_head &); /* Prevent use of these */ sp_head(const sp_head &); /* Prevent use of these */
...@@ -194,24 +198,10 @@ class sp_head : public Sql_alloc ...@@ -194,24 +198,10 @@ class sp_head : public Sql_alloc
longlong created, longlong modified, longlong created, longlong modified,
st_sp_chistics *chistics); st_sp_chistics *chistics);
inline void reset_thd_mem_root(THD *thd) void reset_thd_mem_root(THD *thd);
{
m_thd_root= thd->mem_root; void restore_thd_mem_root(THD *thd);
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;
}
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: private:
...@@ -219,6 +209,7 @@ class sp_head : public Sql_alloc ...@@ -219,6 +209,7 @@ class sp_head : public Sql_alloc
MEM_ROOT m_thd_root; // Temp. store for thd's mem_root MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
Item *m_free_list; // Where the items go Item *m_free_list; // Where the items go
THD *m_thd; // Set if we have reset mem_root THD *m_thd; // Set if we have reset mem_root
char *m_thd_db; // Original thd->db pointer
sp_pcontext *m_pcont; // Parse context sp_pcontext *m_pcont; // Parse context
List<LEX> m_lex; // Temp. store for the other lex List<LEX> m_lex; // Temp. store for the other lex
...@@ -671,8 +662,6 @@ struct st_sp_security_context ...@@ -671,8 +662,6 @@ struct st_sp_security_context
bool changed; bool changed;
uint master_access; uint master_access;
uint db_access; uint db_access;
char *db;
uint db_length;
char *priv_user; char *priv_user;
char priv_host[MAX_HOSTNAME]; char priv_host[MAX_HOSTNAME];
char *user; char *user;
......
...@@ -595,7 +595,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, ...@@ -595,7 +595,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
1 error 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; int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME)); char *dbname=my_strdup((char*) name,MYF(MY_WME));
...@@ -604,62 +605,76 @@ bool mysql_change_db(THD *thd, const char *name) ...@@ -604,62 +605,76 @@ bool mysql_change_db(THD *thd, const char *name)
HA_CREATE_INFO create; HA_CREATE_INFO create;
DBUG_ENTER("mysql_change_db"); 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 */ x_free(dbname); /* purecov: inspected */
send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
DBUG_RETURN(1); /* 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); if ((db_length > NAME_LEN) || check_db_name(dbname))
x_free(dbname); {
DBUG_RETURN(1); net_printf(thd, ER_WRONG_DB_NAME, dbname);
x_free(dbname);
DBUG_RETURN(1);
}
} }
DBUG_PRINT("info",("Use database: %s", dbname)); DBUG_PRINT("info",("Use database: %s", dbname));
#ifndef NO_EMBEDDED_ACCESS_CHECKS if (!empty_is_ok || (dbname && db_length))
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, #ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->priv_user, if (! no_access_check)
thd->priv_host, {
dbname); if (test_all_bits(thd->master_access,DB_ACLS))
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), db_access=DB_ACLS;
thd->priv_user, else
thd->priv_host, db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
dbname); thd->master_access);
my_free(dbname,MYF(0)); if (!(db_access & DB_ACLS) &&
DBUG_RETURN(1); (!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 #endif
(void) sprintf(path,"%s/%s",mysql_data_home,dbname); (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
length=unpack_dirname(path,path); // Convert if not unix length=unpack_dirname(path,path); // Convert if not unix
if (length && path[length-1] == FN_LIBCHAR) if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\' path[length-1]=0; // remove ending '\'
if (access(path,F_OK)) if (access(path,F_OK))
{ {
net_printf(thd,ER_BAD_DB_ERROR,dbname); net_printf(thd,ER_BAD_DB_ERROR,dbname);
my_free(dbname,MYF(0)); my_free(dbname,MYF(0));
DBUG_RETURN(1); DBUG_RETURN(1);
}
} }
send_ok(thd); send_ok(thd);
x_free(thd->db); x_free(thd->db);
thd->db=dbname; // THD::~THD will free this thd->db=dbname; // THD::~THD will free this
thd->db_length=db_length; thd->db_length=db_length;
if (!empty_is_ok || (dbname && db_length))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->db_access=db_access; if (! no_access_check)
thd->db_access=db_access;
#endif #endif
strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
load_db_opt(thd, path, &create); load_db_opt(thd, path, &create);
thd->db_charset= create.default_table_charset ? thd->db_charset= create.default_table_charset ?
create.default_table_charset : create.default_table_charset :
thd->variables.collation_server; thd->variables.collation_server;
thd->variables.collation_database= thd->db_charset; thd->variables.collation_database= thd->db_charset;
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -1090,8 +1090,15 @@ create: ...@@ -1090,8 +1090,15 @@ create:
; ;
sp_name: sp_name:
IDENT_sys '.' IDENT_sys { $$= new sp_name($1, $3); } IDENT_sys '.' IDENT_sys
| IDENT_sys { $$= new sp_name($1); } {
$$= new sp_name($1, $3);
$$->init_qname(YYTHD);
}
| IDENT_sys
{
$$= sp_name_current_db_new(YYTHD, $1);
}
; ;
create_function_tail: create_function_tail:
...@@ -1576,6 +1583,11 @@ sp_proc_stmt: ...@@ -1576,6 +1583,11 @@ sp_proc_stmt:
/* We maybe have one or more SELECT without INTO */ /* We maybe have one or more SELECT without INTO */
lex->sphead->m_multi_results= TRUE; 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. /* Don't add an instruction for empty SET statements.
** (This happens if the SET only contained local variables, ** (This happens if the SET only contained local variables,
** which get their set instructions generated separately.) ** which get their set instructions generated separately.)
...@@ -3913,10 +3925,11 @@ simple_expr: ...@@ -3913,10 +3925,11 @@ simple_expr:
{ $$= new Item_int((char*) "TRUE",1,1); } { $$= new Item_int((char*) "TRUE",1,1); }
| IDENT_sys '(' udf_expr_list ')' | IDENT_sys '(' udf_expr_list ')'
{ {
if (sp_function_exists(YYTHD, &$1)) sp_name *name= sp_name_current_db_new(YYTHD, $1);
if (sp_function_exists(YYTHD, name))
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_name *name= new sp_name($1);
sp_add_fun_to_lex(lex, name); sp_add_fun_to_lex(lex, name);
if ($3) if ($3)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment