Commit 75fec5bd authored by unknown's avatar unknown

Merge rurik.mysql.com:/home/igor/mysql-5.0

into rurik.mysql.com:/home/igor/dev/mysql-5.0-0


mysql-test/r/index_merge.result:
  Auto merged
sql/item_func.cc:
  Auto merged
sql/item_func.h:
  Auto merged
parents b692e9c2 220494bd
...@@ -24,6 +24,7 @@ bk@admin.bk ...@@ -24,6 +24,7 @@ bk@admin.bk
bk@mysql.r18.ru bk@mysql.r18.ru
carsten@tsort.bitbybit.dk carsten@tsort.bitbybit.dk
davida@isil.mysql.com davida@isil.mysql.com
dlenev@brandersnatch.localdomain
dlenev@build.mysql.com dlenev@build.mysql.com
dlenev@mysql.com dlenev@mysql.com
gerberb@ou800.zenez.com gerberb@ou800.zenez.com
......
...@@ -1057,9 +1057,9 @@ ...@@ -1057,9 +1057,9 @@
CREATE TABLE proc ( CREATE TABLE proc (
db char(64) binary DEFAULT '' NOT NULL, db char(64) binary DEFAULT '' NOT NULL,
name char(64) binary DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL,
type enum('FUNCTION','PROCEDURE') NOT NULL, type enum('FUNCTION','PROCEDURE') NOT NULL,
specific_name char(64) binary DEFAULT '' NOT NULL, specific_name char(64) DEFAULT '' NOT NULL,
language enum('SQL') DEFAULT 'SQL' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL,
sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL, sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL,
is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,
......
...@@ -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", "",
...@@ -314,4 +314,24 @@ key1 key2 key3 key4 key5 key6 key7 key8 key9 keyA keyB keyC ...@@ -314,4 +314,24 @@ key1 key2 key3 key4 key5 key6 key7 key8 key9 keyA keyB keyC
11 11 11 11 11 11 11 1013 11 11 11 11 11 11 11 11 11 11 11 1013 11 11 11 11
12 12 12 12 12 12 12 1012 12 12 12 12 12 12 12 12 12 12 12 1012 12 12 12 12
1016 1016 1016 1016 1016 1016 1016 8 1016 1016 1016 1016 1016 1016 1016 1016 1016 1016 1016 8 1016 1016 1016 1016
explain select * from t0 where key1 < 3 or key2 < 4;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 7 Using where
select * from t0 where key1 < 3 or key2 < 4;
key1 key2 key3 key4 key5 key6 key7 key8
1 1 1 1 1 1 1 1023
2 2 2 2 2 2 2 1022
3 3 3 3 3 3 3 1021
update t0 set key8=123 where key1 < 3 or key2 < 4;
select * from t0 where key1 < 3 or key2 < 4;
key1 key2 key3 key4 key5 key6 key7 key8
1 1 1 1 1 1 1 123
2 2 2 2 2 2 2 123
3 3 3 3 3 3 3 123
delete from t0 where key1 < 3 or key2 < 4;
select * from t0 where key1 < 3 or key2 < 4;
key1 key2 key3 key4 key5 key6 key7 key8
select count(*) from t0;
count(*)
1021
drop table t0, t1, t2, t3, t4; drop table t0, t1, t2, t3, t4;
...@@ -144,7 +144,6 @@ insert into t1 values (1); ...@@ -144,7 +144,6 @@ insert into t1 values (1);
show open tables; show open tables;
Database Table In_use Name_locked Database Table In_use Name_locked
test t1 0 0 test t1 0 0
mysql proc 0 0
drop table t1; 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; 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; show create table t1;
......
...@@ -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;
......
use test; use test;
grant usage on *.* to dummy@localhost; grant usage on *.* to user1@localhost;
flush privileges;
drop database if exists db1_secret; drop database if exists db1_secret;
create database db1_secret; create database db1_secret;
use db1_secret; use db1_secret;
...@@ -7,39 +8,104 @@ create table t1 ( u varchar(64), i int ); ...@@ -7,39 +8,104 @@ 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
create function db() returns varchar(64) return database();
show function status like 'db';
Db Name Type Definer Modified Created Security_type Comment
db1_secret db FUNCTION 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); select db();
db()
db1_secret
call db1_secret.stamp(2);
select db1_secret.db();
db1_secret.db()
db1_secret
select * from db1_secret.t1; select * from db1_secret.t1;
ERROR 42000: Access denied for user: 'dummy'@'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 db1_secret.db();
db1_secret.db()
db1_secret
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;
u i u i
root@localhost 1 root@localhost 1
dummy@localhost 2 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
alter function db sql security invoker;
show function status like 'db';
Db Name Type Definer Modified Created Security_type Comment
db1_secret db FUNCTION 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
root@localhost 1 root@localhost 1
dummy@localhost 2 user1@localhost 2
anon@localhost 3 anon@localhost 3
root@localhost 4 root@localhost 4
call stamp(5); select db();
ERROR 42000: Access denied for user: 'dummy'@'localhost' to database 'db1_secret' db()
call stamp(6); db1_secret
call db1_secret.stamp(5);
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
select db1_secret.db();
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
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 procedure stamp; select db1_secret.db();
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
drop database if exists db2;
create database db2;
use db2;
create table t2 (s1 int);
insert into t2 values (0);
grant usage on db2.* to user1@localhost;
grant select on db2.* to user1@localhost;
grant usage on db2.* to user2@localhost;
grant select,insert,update,delete on db2.* to user2@localhost;
flush privileges;
use db2;
create procedure p () insert into t2 values (1);
call p();
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db2'
use db2;
call p();
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db2'
select * from t2;
s1
0
create procedure q () insert into t2 values (2);
call q();
select * from t2;
s1
0
2
use db2;
call q();
select * from t2;
s1
0
2
2
use test; use test;
select type,db,name from mysql.proc;
type db name
FUNCTION db1_secret db
PROCEDURE db1_secret stamp
PROCEDURE db2 p
PROCEDURE db2 q
drop database db1_secret; drop database db1_secret;
delete from mysql.user where user='dummy'; drop database db2;
select type,db,name from mysql.proc;
type db name
delete from mysql.user where user='user1' or user='user2';
...@@ -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'
...@@ -797,6 +786,22 @@ select @c1, @c2| ...@@ -797,6 +786,22 @@ select @c1, @c2|
12 3 12 3
delete from t1| delete from t1|
drop procedure modes| drop procedure modes|
create database sp_db1|
drop database sp_db1|
create database sp_db2|
use sp_db2|
create table t3 ( s char(4), t int )|
insert into t3 values ("abcd", 42), ("dcba", 666)|
use test|
drop database sp_db2|
create database sp_db3|
use sp_db3|
create procedure dummy(out x int)
set x = 42|
use test|
drop database sp_db3|
select type,db,name from mysql.proc where db = 'sp_db3'|
type db name
create procedure bug822(a_id char(16), a_data int) create procedure bug822(a_id char(16), a_data int)
begin begin
declare n int; declare n int;
...@@ -939,23 +944,23 @@ begin ...@@ -939,23 +944,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
...@@ -989,6 +994,24 @@ call bug2614()| ...@@ -989,6 +994,24 @@ call bug2614()|
call bug2614()| call bug2614()|
drop table t3| drop table t3|
drop procedure bug2614| drop procedure bug2614|
create function bug2674 () returns int
return @@sort_buffer_size|
select bug2674()|
bug2674()
262136
drop function bug2674|
create procedure bug3259_1 () begin end|
create procedure BUG3259_2 () begin end|
create procedure Bug3259_3 () begin end|
call BUG3259_1()|
call BUG3259_1()|
call bug3259_2()|
call Bug3259_2()|
call bug3259_3()|
call bUG3259_3()|
drop procedure bUg3259_1|
drop procedure BuG3259_2|
drop procedure BUG3259_3|
drop table if exists fac| drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)| create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned) create procedure ifac(n int unsigned)
...@@ -1029,12 +1052,12 @@ n f ...@@ -1029,12 +1052,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 +1118,7 @@ end while; ...@@ -1095,7 +1118,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 +1145,9 @@ end if; ...@@ -1122,9 +1145,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 +1158,7 @@ drop table primes| ...@@ -1135,7 +1158,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 +1208,19 @@ create procedure bar(x char(16), y int) ...@@ -1185,19 +1208,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;
...@@ -14,6 +14,6 @@ update t1 set n = 3; ...@@ -14,6 +14,6 @@ update t1 set n = 3;
unlock tables; unlock tables;
show status like 'Table_lock%'; show status like 'Table_lock%';
Variable_name Value Variable_name Value
Table_locks_immediate 4 Table_locks_immediate 3
Table_locks_waited 1 Table_locks_waited 1
drop table t1; drop table t1;
...@@ -267,5 +267,15 @@ select * from t3 where ...@@ -267,5 +267,15 @@ select * from t3 where
key5=5 or key6=6 or key7=7 or key8=8 or key5=5 or key6=6 or key7=7 or key8=8 or
key9=9 or keyA=10 or keyB=11 or keyC=12; key9=9 or keyA=10 or keyB=11 or keyC=12;
# Test for Bug#3183
explain select * from t0 where key1 < 3 or key2 < 4;
select * from t0 where key1 < 3 or key2 < 4;
update t0 set key8=123 where key1 < 3 or key2 < 4;
select * from t0 where key1 < 3 or key2 < 4;
delete from t0 where key1 < 3 or key2 < 4;
select * from t0 where key1 < 3 or key2 < 4;
select count(*) from t0;
drop table t0, t1, t2, t3, t4; drop table t0, t1, t2, t3, t4;
...@@ -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
# #
......
...@@ -7,8 +7,9 @@ connect (con1root,localhost,root,,); ...@@ -7,8 +7,9 @@ connect (con1root,localhost,root,,);
connection con1root; connection con1root;
use test; use test;
# Create dummy user with no particular access rights # Create user user1 with no particular access rights
grant usage on *.* to dummy@localhost; grant usage on *.* to user1@localhost;
flush privileges;
--disable_warnings --disable_warnings
drop database if exists db1_secret; drop database if exists db1_secret;
...@@ -20,26 +21,32 @@ use db1_secret; ...@@ -20,26 +21,32 @@ use db1_secret;
create table t1 ( u varchar(64), i int ); create table t1 ( u varchar(64), i int );
# Our test procedure # A test procedure and function
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';
create function db() returns varchar(64) return database();
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show function status like 'db';
# root can, of course # root can, of course
call stamp(1); call stamp(1);
select * from t1; select * from t1;
select db();
connect (con2dummy,localhost,dummy,,); connect (con2user1,localhost,user1,,);
connect (con3anon,localhost,anon,,); connect (con3anon,localhost,anon,,);
# #
# Dummy can # User1 can
# #
connection con2dummy; connection con2user1;
# This should work... # This should work...
call stamp(2); call db1_secret.stamp(2);
select db1_secret.db();
# ...but not this # ...but not this
--error 1044 --error 1044
...@@ -51,7 +58,8 @@ select * from db1_secret.t1; ...@@ -51,7 +58,8 @@ select * from db1_secret.t1;
connection con3anon; connection con3anon;
# This should work... # This should work...
call stamp(3); call db1_secret.stamp(3);
select db1_secret.db();
# ...but not this # ...but not this
--error 1044 --error 1044
...@@ -67,21 +75,28 @@ select * from t1; ...@@ -67,21 +75,28 @@ 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';
alter function db sql security invoker;
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show function status like 'db';
# root still can # root still can
call stamp(4); call stamp(4);
select * from t1; select * from t1;
select db();
# #
# Dummy cannot # User1 cannot
# #
connection con2dummy; connection con2user1;
# This should not work # This should not work
--error 1044 --error 1044
call stamp(5); call db1_secret.stamp(5);
--error 1044
select db1_secret.db();
# #
# Anonymous cannot # Anonymous cannot
...@@ -90,11 +105,69 @@ connection con3anon; ...@@ -90,11 +105,69 @@ connection con3anon;
# This should not work # This should not work
--error 1044 --error 1044
call stamp(6); call db1_secret.stamp(6);
--error 1044
select db1_secret.db();
#
# BUG#2777
#
connection con1root;
--disable_warnings
drop database if exists db2;
--enable_warnings
create database db2;
use db2;
create table t2 (s1 int);
insert into t2 values (0);
grant usage on db2.* to user1@localhost;
grant select on db2.* to user1@localhost;
grant usage on db2.* to user2@localhost;
grant select,insert,update,delete on db2.* to user2@localhost;
flush privileges;
connection con2user1;
use db2;
create procedure p () insert into t2 values (1);
# Check that this doesn't work.
--error 1044
call p();
connect (con4user2,localhost,user2,,);
connection con4user2;
use db2;
# This should not work, since p is executed with definer's (user1's) rights.
--error 1044
call p();
select * from t2;
create procedure q () insert into t2 values (2);
call q();
select * from t2;
connection con2user1;
use db2;
# This should work
call q();
select * from t2;
# Clean up # Clean up
connection con1root; connection con1root;
drop procedure stamp;
use test; use test;
select type,db,name from mysql.proc;
drop database db1_secret; drop database db1_secret;
delete from mysql.user where user='dummy'; drop database db2;
# Make sure the routines are gone
select type,db,name from mysql.proc;
# Get rid of the users
delete from mysql.user where user='user1' or user='user2';
...@@ -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);
...@@ -920,6 +905,32 @@ delete from t1| ...@@ -920,6 +905,32 @@ delete from t1|
drop procedure modes| drop procedure modes|
# Check that dropping a database without routines works.
# (Dropping with routines is tested in sp-security.test)
# First an empty db.
create database sp_db1|
drop database sp_db1|
# Again, with a table.
create database sp_db2|
use sp_db2|
# Just put something in here...
create table t3 ( s char(4), t int )|
insert into t3 values ("abcd", 42), ("dcba", 666)|
use test|
drop database sp_db2|
# And yet again, with just a procedure.
create database sp_db3|
use sp_db3|
create procedure dummy(out x int)
set x = 42|
use test|
drop database sp_db3|
# Check that it's gone
select type,db,name from mysql.proc where db = 'sp_db3'|
# #
# Test cases for old bugs # Test cases for old bugs
# #
...@@ -1094,9 +1105,9 @@ begin ...@@ -1094,9 +1105,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()|
...@@ -1138,6 +1149,35 @@ call bug2614()| ...@@ -1138,6 +1149,35 @@ call bug2614()|
drop table t3| drop table t3|
drop procedure bug2614| drop procedure bug2614|
#
# BUG#2674
#
create function bug2674 () returns int
return @@sort_buffer_size|
select bug2674()|
drop function bug2674|
#
# BUG#3259
#
create procedure bug3259_1 () begin end|
create procedure BUG3259_2 () begin end|
create procedure Bug3259_3 () begin end|
call BUG3259_1()|
call BUG3259_1()|
call bug3259_2()|
call Bug3259_2()|
call bug3259_3()|
call bUG3259_3()|
drop procedure bUg3259_1|
drop procedure BuG3259_2|
drop procedure BUG3259_3|
# #
# Some "real" examples # Some "real" examples
...@@ -1168,11 +1208,11 @@ end| ...@@ -1168,11 +1208,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 +1289,7 @@ begin ...@@ -1249,7 +1289,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 +1301,7 @@ select * from primes where i=45 or i=100 or i=199| ...@@ -1261,7 +1301,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 +1348,13 @@ drop procedure fib| ...@@ -1308,13 +1348,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 ;|
......
...@@ -290,9 +290,9 @@ if test ! -f $mdata/proc.frm ...@@ -290,9 +290,9 @@ if test ! -f $mdata/proc.frm
then then
c_p="$c_p CREATE TABLE proc (" c_p="$c_p CREATE TABLE proc ("
c_p="$c_p db char(64) binary DEFAULT '' NOT NULL," c_p="$c_p db char(64) binary DEFAULT '' NOT NULL,"
c_p="$c_p name char(64) binary DEFAULT '' NOT NULL," c_p="$c_p name char(64) DEFAULT '' NOT NULL,"
c_p="$c_p type enum('FUNCTION','PROCEDURE') NOT NULL," c_p="$c_p type enum('FUNCTION','PROCEDURE') NOT NULL,"
c_p="$c_p specific_name char(64) binary DEFAULT '' NOT NULL," c_p="$c_p specific_name char(64) DEFAULT '' NOT NULL,"
c_p="$c_p language enum('SQL') DEFAULT 'SQL' NOT NULL," c_p="$c_p language enum('SQL') DEFAULT 'SQL' NOT NULL,"
c_p="$c_p sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL," c_p="$c_p sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL,"
c_p="$c_p is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL," c_p="$c_p is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,"
......
...@@ -141,9 +141,9 @@ unique index (name) ...@@ -141,9 +141,9 @@ unique index (name)
CREATE TABLE IF NOT EXISTS proc ( CREATE TABLE IF NOT EXISTS proc (
db char(64) binary DEFAULT '' NOT NULL, db char(64) binary DEFAULT '' NOT NULL,
name char(64) binary DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL,
type enum('FUNCTION','PROCEDURE') NOT NULL, type enum('FUNCTION','PROCEDURE') NOT NULL,
specific_name char(64) binary DEFAULT '' NOT NULL, specific_name char(64) DEFAULT '' NOT NULL,
language enum('SQL') DEFAULT 'SQL' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL,
sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL, sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL,
is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,
...@@ -179,3 +179,7 @@ CREATE TABLE IF NOT EXISTS proc ( ...@@ -179,3 +179,7 @@ CREATE TABLE IF NOT EXISTS proc (
comment char(64) binary DEFAULT '' NOT NULL, comment char(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (db,name,type) PRIMARY KEY (db,name,type)
) comment='Stored Procedures'; ) comment='Stored Procedures';
# Correct the name fields to not binary
ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL,
MODIFY specific_name char(64) DEFAULT '' NOT NULL;
...@@ -3127,6 +3127,25 @@ longlong Item_func_is_used_lock::val_int() ...@@ -3127,6 +3127,25 @@ longlong Item_func_is_used_lock::val_int()
return ull->thread_id; 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 int
Item_func_sp::execute(Item **itp) Item_func_sp::execute(Item **itp)
{ {
...@@ -3138,9 +3157,13 @@ Item_func_sp::execute(Item **itp) ...@@ -3138,9 +3157,13 @@ Item_func_sp::execute(Item **itp)
#endif #endif
if (! m_sp) if (! m_sp)
m_sp= sp_find_function(thd, &m_name); m_sp= sp_find_function(thd, m_name);
if (! m_sp) if (! m_sp)
{
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
"FUNCTION", m_name->m_qname);
DBUG_RETURN(-1); DBUG_RETURN(-1);
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
sp_change_security_context(thd, m_sp, &save_ctx); sp_change_security_context(thd, m_sp, &save_ctx);
...@@ -3161,12 +3184,14 @@ Item_func_sp::field_type() const ...@@ -3161,12 +3184,14 @@ Item_func_sp::field_type() const
DBUG_ENTER("Item_func_sp::field_type"); DBUG_ENTER("Item_func_sp::field_type");
if (! 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) if (m_sp)
{ {
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns)); DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
DBUG_RETURN(m_sp->m_returns); DBUG_RETURN(m_sp->m_returns);
} }
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
"FUNCTION", m_name->m_qname);
DBUG_RETURN(MYSQL_TYPE_STRING); DBUG_RETURN(MYSQL_TYPE_STRING);
} }
...@@ -3177,11 +3202,13 @@ Item_func_sp::result_type() const ...@@ -3177,11 +3202,13 @@ Item_func_sp::result_type() const
DBUG_PRINT("info", ("m_sp = %p", m_sp)); DBUG_PRINT("info", ("m_sp = %p", m_sp));
if (! 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) if (m_sp)
{ {
DBUG_RETURN(m_sp->result()); DBUG_RETURN(m_sp->result());
} }
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
"FUNCTION", m_name->m_qname);
DBUG_RETURN(STRING_RESULT); DBUG_RETURN(STRING_RESULT);
} }
...@@ -3191,8 +3218,13 @@ Item_func_sp::fix_length_and_dec() ...@@ -3191,8 +3218,13 @@ Item_func_sp::fix_length_and_dec()
DBUG_ENTER("Item_func_sp::fix_length_and_dec"); DBUG_ENTER("Item_func_sp::fix_length_and_dec");
if (! m_sp) if (! m_sp)
m_sp= sp_find_function(current_thd, &m_name); m_sp= sp_find_function(current_thd, m_name);
if (m_sp) if (! m_sp)
{
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
"FUNCTION", m_name->m_qname);
}
else
{ {
switch (m_sp->result()) { switch (m_sp->result()) {
case STRING_RESULT: case STRING_RESULT:
......
...@@ -1075,32 +1075,26 @@ enum Cast_target ...@@ -1075,32 +1075,26 @@ enum Cast_target
*/ */
class sp_head; class sp_head;
class sp_name;
class Item_func_sp :public Item_func class Item_func_sp :public Item_func
{ {
private: private:
LEX_STRING m_name; sp_name *m_name;
mutable sp_head *m_sp; mutable sp_head *m_sp;
int execute(Item **itp); int execute(Item **itp);
public: public:
Item_func_sp(LEX_STRING name) Item_func_sp(sp_name *name);
:Item_func(), m_name(name), m_sp(NULL)
{}
Item_func_sp(LEX_STRING name, List<Item> &list) Item_func_sp(sp_name *name, List<Item> &list);
:Item_func(list), m_name(name), m_sp(NULL)
{}
virtual ~Item_func_sp() virtual ~Item_func_sp()
{} {}
const char *func_name() const const char *func_name() const;
{
return m_name.str;
}
enum enum_field_types field_type() const; enum enum_field_types field_type() const;
...@@ -1116,7 +1110,10 @@ class Item_func_sp :public Item_func ...@@ -1116,7 +1110,10 @@ class Item_func_sp :public Item_func
Item *it; Item *it;
if (execute(&it)) if (execute(&it))
{
null_value= 1;
return 0.0; return 0.0;
}
return it->val(); return it->val();
} }
...@@ -1125,7 +1122,10 @@ class Item_func_sp :public Item_func ...@@ -1125,7 +1122,10 @@ class Item_func_sp :public Item_func
Item *it; Item *it;
if (execute(&it)) if (execute(&it))
{
null_value= 1;
return NULL; return NULL;
}
return it->val_str(str); return it->val_str(str);
} }
......
...@@ -87,7 +87,16 @@ class QUICK_SELECT_I ...@@ -87,7 +87,16 @@ class QUICK_SELECT_I
QUICK_SELECT_I(); QUICK_SELECT_I();
virtual ~QUICK_SELECT_I(){}; virtual ~QUICK_SELECT_I(){};
/*
Call init() immediately after creation of quick select. if init() call
fails, reset() or get_next() must not be called.
*/
virtual int init() = 0; virtual int init() = 0;
/*
Call reset() before first get_next call. get_next must not be called if
reset() call fails.
*/
virtual int reset(void) = 0; virtual int reset(void) = 0;
virtual int get_next() = 0; /* get next record to retrieve */ virtual int get_next() = 0; /* get next record to retrieve */
virtual bool reverse_sorted() = 0; virtual bool reverse_sorted() = 0;
......
...@@ -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"
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include "sql_acl.h"
#include "sp.h" #include "sp.h"
#include "sp_head.h" #include "sp_head.h"
#include "sp_cache.h" #include "sp_cache.h"
...@@ -23,7 +24,7 @@ ...@@ -23,7 +24,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,
...@@ -58,21 +59,26 @@ enum ...@@ -58,21 +59,26 @@ enum
/* *opened=true means we opened ourselves */ /* *opened=true means we opened ourselves */
static int 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) enum thr_lock_type ltype, TABLE **tablep, bool *opened)
{ {
TABLE *table; TABLE *table;
byte key[64+64+1]; // db, name, type byte key[64+64+1]; // db, name, type
uint keylen; uint keylen;
DBUG_ENTER("db_find_routine_aux"); 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 // Put the key used to read the row together
memset(key, (int)' ', 64); // QQ Empty db for now keylen= name->m_db.length;
keylen= namelen;
if (keylen > 64) if (keylen > 64)
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 memset(key+64+keylen, (int)' ', 64-keylen); // Pad with space
key[128]= type; key[128]= type;
keylen= sizeof(key); keylen= sizeof(key);
...@@ -112,7 +118,7 @@ db_find_routine_aux(THD *thd, int type, char *name, uint namelen, ...@@ -112,7 +118,7 @@ db_find_routine_aux(THD *thd, int type, char *name, uint namelen,
static int 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); extern int yyparse(void *thd);
TABLE *table; TABLE *table;
...@@ -129,9 +135,10 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) ...@@ -129,9 +135,10 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
String str(buff, sizeof(buff), &my_charset_bin); String str(buff, sizeof(buff), &my_charset_bin);
ulong sql_mode; ulong sql_mode;
DBUG_ENTER("db_find_routine"); 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) if (ret != SP_OK)
goto done; goto done;
...@@ -211,6 +218,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) ...@@ -211,6 +218,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, 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;
...@@ -220,7 +229,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) ...@@ -220,7 +229,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
if (!(defstr= create_string(thd, &deflen, if (!(defstr= create_string(thd, &deflen,
type, type,
name, namelen, name,
params, strlen(params), params, strlen(params),
returns, strlen(returns), returns, strlen(returns),
body, strlen(body), body, strlen(body),
...@@ -230,12 +239,32 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) ...@@ -230,12 +239,32 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
goto done; 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
* do it is, is to call mysql_init_query(), but this unfortunately
* resets teh value_list where we keep the CALL parameters. So we
* copy the list and then restore it.
*/
List<Item> vals= thd->lex->value_list;
mysql_init_query(thd, TRUE);
lex_start(thd, (uchar*)defstr, deflen); lex_start(thd, (uchar*)defstr, deflen);
thd->lex->value_list= vals;
}
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)
...@@ -247,6 +276,9 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) ...@@ -247,6 +276,9 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, 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);
...@@ -257,6 +289,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp) ...@@ -257,6 +289,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
} }
done: done:
if (opened) if (opened)
close_thread_tables(thd); close_thread_tables(thd);
DBUG_RETURN(ret); DBUG_RETURN(ret);
...@@ -289,6 +322,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) ...@@ -289,6 +322,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;
} }
table->field[MYSQL_PROC_FIELD_DB]->
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]->
...@@ -329,15 +364,16 @@ db_create_routine(THD *thd, int type, sp_head *sp) ...@@ -329,15 +364,16 @@ db_create_routine(THD *thd, int type, sp_head *sp)
static int 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; TABLE *table;
int ret; int ret;
bool opened; bool opened;
DBUG_ENTER("db_drop_routine"); 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 (ret == SP_OK)
{ {
if (table->file->delete_row(table->record[0])) if (table->file->delete_row(table->record[0]))
...@@ -351,7 +387,7 @@ db_drop_routine(THD *thd, int type, char *name, uint namelen) ...@@ -351,7 +387,7 @@ db_drop_routine(THD *thd, int type, char *name, uint namelen)
static int 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, char *newname, uint newnamelen,
st_sp_chistics *chistics) st_sp_chistics *chistics)
{ {
...@@ -359,9 +395,10 @@ db_update_routine(THD *thd, int type, char *name, uint namelen, ...@@ -359,9 +395,10 @@ db_update_routine(THD *thd, int type, char *name, uint namelen,
int ret; int ret;
bool opened; bool opened;
DBUG_ENTER("db_update_routine"); 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) if (ret == SP_OK)
{ {
store_record(table,record[1]); store_record(table,record[1]);
...@@ -395,6 +432,7 @@ struct st_used_field ...@@ -395,6 +432,7 @@ struct st_used_field
static struct st_used_field init_fields[]= static struct st_used_field init_fields[]=
{ {
{ "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},
...@@ -415,14 +453,20 @@ print_field_values(THD *thd, TABLE *table, ...@@ -415,14 +453,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++)
...@@ -439,10 +483,10 @@ print_field_values(THD *thd, TABLE *table, ...@@ -439,10 +483,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;
} }
...@@ -545,21 +589,87 @@ db_show_routine_status(THD *thd, int type, const char *wild) ...@@ -545,21 +589,87 @@ db_show_routine_status(THD *thd, int type, const char *wild)
} }
/* Drop all routines in database 'db' */
int
sp_drop_db_routines(THD *thd, char *db)
{
TABLE *table;
byte key[64]; // db
uint keylen;
int ret;
DBUG_ENTER("sp_drop_db_routines");
DBUG_PRINT("enter", ("db: %s", db));
// Put the key used to read the row together
keylen= strlen(db);
if (keylen > 64)
keylen= 64;
memcpy(key, db, keylen);
memset(key+keylen, (int)' ', 64-keylen); // Pad with space
keylen= sizeof(key);
for (table= thd->open_tables ; table ; table= table->next)
if (strcmp(table->table_cache_key, "mysql") == 0 &&
strcmp(table->real_name, "proc") == 0)
break;
if (! table)
{
TABLE_LIST tables;
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
tables.real_name= tables.alias= (char*)"proc";
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
}
ret= SP_OK;
table->file->index_init(0);
if (! table->file->index_read(table->record[0],
key, keylen, HA_READ_KEY_EXACT))
{
int nxtres;
bool deleted= FALSE;
do {
if (! table->file->delete_row(table->record[0]))
deleted= TRUE; /* We deleted something */
else
{
ret= SP_DELETE_ROW_FAILED;
nxtres= 0;
break;
}
} while (! (nxtres= table->file->index_next_same(table->record[0],
key, keylen)));
if (nxtres != HA_ERR_END_OF_FILE)
ret= SP_KEY_NOT_FOUND;
if (deleted)
sp_cache_invalidate();
}
close_thread_tables(thd);
DBUG_RETURN(ret);
}
/***************************************************************************** /*****************************************************************************
PROCEDURE PROCEDURE
******************************************************************************/ ******************************************************************************/
sp_head * sp_head *
sp_find_procedure(THD *thd, LEX_STRING *name) sp_find_procedure(THD *thd, sp_name *name)
{ {
sp_head *sp; sp_head *sp;
DBUG_ENTER("sp_find_procedure"); 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, if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK)
name->str, name->length, &sp) == SP_OK)
sp_cache_insert(&thd->sp_proc_cache, sp); sp_cache_insert(&thd->sp_proc_cache, sp);
} }
...@@ -580,40 +690,40 @@ sp_create_procedure(THD *thd, sp_head *sp) ...@@ -580,40 +690,40 @@ sp_create_procedure(THD *thd, sp_head *sp)
int int
sp_drop_procedure(THD *thd, char *name, uint namelen) sp_drop_procedure(THD *thd, sp_name *name)
{ {
int ret; int ret;
DBUG_ENTER("sp_drop_procedure"); 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); sp_cache_remove(&thd->sp_proc_cache, name);
ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen); ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
int int
sp_update_procedure(THD *thd, char *name, uint namelen, sp_update_procedure(THD *thd, sp_name *name,
char *newname, uint newnamelen, char *newname, uint newnamelen,
st_sp_chistics *chistics) st_sp_chistics *chistics)
{ {
int ret; int ret;
DBUG_ENTER("sp_update_procedure"); 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); sp_cache_remove(&thd->sp_proc_cache, name);
ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name,
newname, newnamelen, chistics); newname, newnamelen, chistics);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
int int
sp_show_create_procedure(THD *thd, LEX_STRING *name) sp_show_create_procedure(THD *thd, sp_name *name)
{ {
sp_head *sp; sp_head *sp;
DBUG_ENTER("sp_show_create_procedure"); 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))) if ((sp= sp_find_procedure(thd, name)))
{ {
...@@ -642,16 +752,15 @@ sp_show_status_procedure(THD *thd, const char *wild) ...@@ -642,16 +752,15 @@ sp_show_status_procedure(THD *thd, const char *wild)
******************************************************************************/ ******************************************************************************/
sp_head * sp_head *
sp_find_function(THD *thd, LEX_STRING *name) sp_find_function(THD *thd, sp_name *name)
{ {
sp_head *sp; sp_head *sp;
DBUG_ENTER("sp_find_function"); 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, if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK)
name->str, name->length, &sp) != SP_OK)
sp= NULL; sp= NULL;
else else
sp_cache_insert(&thd->sp_func_cache, sp); sp_cache_insert(&thd->sp_func_cache, sp);
...@@ -673,40 +782,40 @@ sp_create_function(THD *thd, sp_head *sp) ...@@ -673,40 +782,40 @@ sp_create_function(THD *thd, sp_head *sp)
int int
sp_drop_function(THD *thd, char *name, uint namelen) sp_drop_function(THD *thd, sp_name *name)
{ {
int ret; int ret;
DBUG_ENTER("sp_drop_function"); 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); sp_cache_remove(&thd->sp_func_cache, name);
ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen); ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
int int
sp_update_function(THD *thd, char *name, uint namelen, sp_update_function(THD *thd, sp_name *name,
char *newname, uint newnamelen, char *newname, uint newnamelen,
st_sp_chistics *chistics) st_sp_chistics *chistics)
{ {
int ret; int ret;
DBUG_ENTER("sp_update_procedure"); 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); sp_cache_remove(&thd->sp_func_cache, name);
ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name,
newname, newnamelen, chistics); newname, newnamelen, chistics);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
int int
sp_show_create_function(THD *thd, LEX_STRING *name) sp_show_create_function(THD *thd, sp_name *name)
{ {
sp_head *sp; sp_head *sp;
DBUG_ENTER("sp_show_create_function"); 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))) if ((sp= sp_find_function(thd, name)))
{ {
...@@ -728,18 +837,17 @@ sp_show_status_function(THD *thd, const char *wild) ...@@ -728,18 +837,17 @@ sp_show_status_function(THD *thd, const char *wild)
} }
// QQ Temporary until the function call detection in sql_lex has been reworked.
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;
DBUG_ENTER("sp_function_exists"); 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, db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
name->str, name->length, TL_READ, name, TL_READ,
&table, &opened) == SP_OK) &table, &opened) == SP_OK)
ret= TRUE; ret= TRUE;
if (opened) if (opened)
...@@ -758,13 +866,14 @@ sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first) ...@@ -758,13 +866,14 @@ sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first)
void 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)); LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING));
ls->str= sql_strmake(fun.str, fun.length); ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length);
ls->length= fun.length; ls->length= fun->m_qname.length;
my_hash_insert(&lex->spfuns, (byte *)ls); my_hash_insert(&lex->spfuns, (byte *)ls);
} }
...@@ -793,15 +902,25 @@ sp_cache_functions(THD *thd, LEX *lex) ...@@ -793,15 +902,25 @@ sp_cache_functions(THD *thd, LEX *lex)
for (uint i=0 ; i < h->records ; i++) for (uint i=0 ; i < h->records ; i++)
{ {
LEX_STRING *ls= (LEX_STRING *)hash_element(h, 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; sp_head *sp;
LEX *oldlex= thd->lex; LEX *oldlex= thd->lex;
LEX *newlex= new st_lex; LEX *newlex= new st_lex;
thd->lex= newlex; 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); ret= sp_cache_functions(thd, newlex);
delete newlex; delete newlex;
...@@ -827,7 +946,7 @@ sp_cache_functions(THD *thd, LEX *lex) ...@@ -827,7 +946,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,
...@@ -836,12 +955,15 @@ create_string(THD *thd, ulong *lenp, ...@@ -836,12 +955,15 @@ create_string(THD *thd, ulong *lenp,
char *buf, *ptr; char *buf, *ptr;
ulong buflen; 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))) if (!(buf= thd->alloc(buflen)))
return 0; return 0;
ptr= strxmov(buf, "CREATE ", (type == TYPE_ENUM_FUNCTION) ? "FUNCTION" : "PROCEDURE", ptr= strxmov(buf, "CREATE ",
" `", name, "`(", params, ")", NullS); (type == TYPE_ENUM_FUNCTION) ? "FUNCTION" : "PROCEDURE",
" `", 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);
...@@ -860,3 +982,148 @@ create_string(THD *thd, ulong *lenp, ...@@ -860,3 +982,148 @@ 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);
}
}
/*
Change database.
SYNOPSIS
sp_change_db()
thd Thread handler
name Database name
empty_is_ok True= it's ok with "" as name
no_access_check True= don't do access check
DESCRIPTION
This is the same as mysql_change_db(), but with some extra
arguments for Stored Procedure usage; doing implicit "use"
when executing an SP in a different database.
We also use different error routines, since this might be
invoked from a function when executing a query or statement.
Note: We would have prefered to reuse mysql_change_db(), but
the error handling in particular made that too awkward, so
we (reluctantly) have a "copy" here.
RETURN VALUES
0 ok
1 error
*/
int
sp_change_db(THD *thd, char *name, bool no_access_check)
{
int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
ulong db_access;
HA_CREATE_INFO create;
DBUG_ENTER("sp_change_db");
DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
db_length= (!dbname ? 0 : strip_sp(dbname));
if (dbname && db_length)
{
if ((db_length > NAME_LEN) || check_db_name(dbname))
{
my_printf_error(ER_WRONG_DB_NAME, ER(ER_WRONG_DB_NAME), MYF(0), dbname);
x_free(dbname);
DBUG_RETURN(1);
}
}
if (dbname && db_length)
{
#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)))
{
my_printf_error(ER_DBACCESS_DENIED_ERROR, ER(ER_DBACCESS_DENIED_ERROR),
MYF(0),
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))
{
my_printf_error(ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR), MYF(0), dbname);
my_free(dbname,MYF(0));
DBUG_RETURN(1);
}
}
x_free(thd->db);
thd->db=dbname; // THD::~THD will free this
thd->db_length=db_length;
if (dbname && db_length)
{
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);
}
...@@ -28,59 +28,77 @@ ...@@ -28,59 +28,77 @@
#define SP_PARSE_ERROR -6 #define SP_PARSE_ERROR -6
#define SP_INTERNAL_ERROR -7 #define SP_INTERNAL_ERROR -7
/* Drop all routines in database 'db' */
int
sp_drop_db_routines(THD *thd, char *db);
sp_head * sp_head *
sp_find_procedure(THD *thd, LEX_STRING *name); sp_find_procedure(THD *thd, sp_name *name);
int int
sp_create_procedure(THD *thd, sp_head *sp); sp_create_procedure(THD *thd, sp_head *sp);
int int
sp_drop_procedure(THD *thd, char *name, uint namelen); sp_drop_procedure(THD *thd, sp_name *name);
int int
sp_update_procedure(THD *thd, char *name, uint namelen, sp_update_procedure(THD *thd, sp_name *name,
char *newname, uint newnamelen, char *newname, uint newnamelen,
st_sp_chistics *chistics); st_sp_chistics *chistics);
int int
sp_show_create_procedure(THD *thd, LEX_STRING *name); sp_show_create_procedure(THD *thd, sp_name *name);
int int
sp_show_status_procedure(THD *thd, const char *wild); sp_show_status_procedure(THD *thd, const char *wild);
sp_head * sp_head *
sp_find_function(THD *thd, LEX_STRING *name); sp_find_function(THD *thd, sp_name *name);
int int
sp_create_function(THD *thd, sp_head *sp); sp_create_function(THD *thd, sp_head *sp);
int int
sp_drop_function(THD *thd, char *name, uint namelen); sp_drop_function(THD *thd, sp_name *name);
int int
sp_update_function(THD *thd, char *name, uint namelen, sp_update_function(THD *thd, sp_name *name,
char *newname, uint newnamelen, char *newname, uint newnamelen,
st_sp_chistics *chistics); st_sp_chistics *chistics);
int int
sp_show_create_function(THD *thd, LEX_STRING *name); sp_show_create_function(THD *thd, sp_name *name);
int int
sp_show_status_function(THD *thd, const char *wild); sp_show_status_function(THD *thd, const char *wild);
// QQ Temporary until the function call detection in sql_lex has been reworked.
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
// do anything else. // do anything else.
void void
sp_add_fun_to_lex(LEX *lex, LEX_STRING fun); sp_add_fun_to_lex(LEX *lex, sp_name *fun);
void void
sp_merge_funs(LEX *dst, LEX *src); 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_ */
...@@ -71,7 +71,7 @@ sp_cache_insert(sp_cache **cp, sp_head *sp) ...@@ -71,7 +71,7 @@ sp_cache_insert(sp_cache **cp, sp_head *sp)
} }
sp_head * sp_head *
sp_cache_lookup(sp_cache **cp, char *name, uint namelen) sp_cache_lookup(sp_cache **cp, sp_name *name)
{ {
ulong v; ulong v;
sp_cache *c= *cp; sp_cache *c= *cp;
...@@ -89,11 +89,11 @@ sp_cache_lookup(sp_cache **cp, char *name, uint namelen) ...@@ -89,11 +89,11 @@ sp_cache_lookup(sp_cache **cp, char *name, uint namelen)
c->version= v; c->version= v;
return NULL; return NULL;
} }
return c->lookup(name, namelen); return c->lookup(name->m_qname.str, name->m_qname.length);
} }
bool bool
sp_cache_remove(sp_cache **cp, char *name, uint namelen) sp_cache_remove(sp_cache **cp, sp_name *name)
{ {
sp_cache *c= *cp; sp_cache *c= *cp;
bool found= FALSE; bool found= FALSE;
...@@ -109,18 +109,28 @@ sp_cache_remove(sp_cache **cp, char *name, uint namelen) ...@@ -109,18 +109,28 @@ sp_cache_remove(sp_cache **cp, char *name, uint namelen)
if (c->version < v) if (c->version < v)
c->remove_all(); c->remove_all();
else else
found= c->remove(name, namelen); found= c->remove(name->m_qname.str, name->m_qname.length);
c->version= v+1; c->version= v+1;
} }
return found; return found;
} }
void
sp_cache_invalidate()
{
pthread_mutex_lock(&Cversion_lock); // LOCK
Cversion++;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
}
static byte * 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
......
...@@ -35,10 +35,13 @@ void sp_cache_clear(sp_cache **cp); ...@@ -35,10 +35,13 @@ void sp_cache_clear(sp_cache **cp);
void sp_cache_insert(sp_cache **cp, sp_head *sp); void sp_cache_insert(sp_cache **cp, sp_head *sp);
/* Lookup an SP in cache */ /* 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 */ /* 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);
/* Invalidate a cache */
void sp_cache_invalidate();
/* /*
......
...@@ -130,6 +130,52 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) ...@@ -130,6 +130,52 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
DBUG_RETURN(it); 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 * void *
sp_head::operator new(size_t size) sp_head::operator new(size_t size)
{ {
...@@ -178,22 +224,42 @@ sp_head::init(LEX *lex) ...@@ -178,22 +224,42 @@ sp_head::init(LEX *lex)
lex->spcont= m_pcont= new sp_pcontext(); lex->spcont= m_pcont= new sp_pcontext();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); 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_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_qname.str= m_db.str= m_name.str= m_params.str= m_retstr.str=
m_name.length= m_params.length= m_retstr.length= m_body.length= m_body.str= m_defstr.str= 0;
m_defstr.length= 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; DBUG_VOID_RETURN;
} }
void 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"); DBUG_ENTER("sp_head::init_strings");
/* During parsing, we must use thd->mem_root */ /* During parsing, we must use thd->mem_root */
MEM_ROOT *root= &thd->mem_root; MEM_ROOT *root= &thd->mem_root;
DBUG_PRINT("info", ("name: %*s", name->length, name->str)); DBUG_PRINT("info", ("name: %*.s%*s",
m_name.length= name->length; name->m_db.length, name->m_db.str,
m_name.str= strmake_root(root, name->str, name->length); 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.length= m_param_end- m_param_begin;
m_params.str= strmake_root(root, m_params.str= strmake_root(root,
(char *)m_param_begin, m_params.length); (char *)m_param_begin, m_params.length);
...@@ -271,30 +337,22 @@ int ...@@ -271,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)
{
uint i= 0;
char *p= olddbptr;
/* Fast inline strncpy without padding... */ olddbptr= thd->db;
while (*p && i < sizeof(olddbname)) if ((ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0)))
olddbname[i++]= *p++; goto done;
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();
...@@ -331,20 +389,20 @@ sp_head::execute(THD *thd) ...@@ -331,20 +389,20 @@ sp_head::execute(THD *thd)
continue; continue;
} }
} }
} while (ret == 0 && !thd->killed && !thd->query_error); } while (ret == 0 && !thd->killed && !thd->query_error &&
!thd->net.report_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 || thd->net.report_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);
} }
...@@ -496,7 +554,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) ...@@ -496,7 +554,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
ret= execute(thd); ret= execute(thd);
// Don't copy back OUT values if we got an error // Don't copy back OUT values if we got an error
if (ret == 0 && csize > 0) if (ret)
{
if (thd->net.report_error)
send_error(thd, 0, NullS);
}
else if (csize > 0)
{ {
List_iterator_fast<Item> li(*args); List_iterator_fast<Item> li(*args);
Item *it; Item *it;
...@@ -711,6 +774,32 @@ sp_head::set_info(char *definer, uint definerlen, ...@@ -711,6 +774,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)
{ {
...@@ -796,7 +885,10 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex) ...@@ -796,7 +885,10 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
thd->lex->unit.thd= thd; // QQ Not reentrant thd->lex->unit.thd= thd; // QQ Not reentrant
freelist= thd->free_list; freelist= thd->free_list;
thd->free_list= NULL; thd->free_list= NULL;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id= query_id++; thd->query_id= query_id++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
// Copy WHERE clause pointers to avoid damaging by optimisation // Copy WHERE clause pointers to avoid damaging by optimisation
// Also clear ref_pointer_arrays. // Also clear ref_pointer_arrays.
...@@ -1089,10 +1181,13 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) ...@@ -1089,10 +1181,13 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
DBUG_RETURN(res); DBUG_RETURN(res);
} }
/* ------------------------------------------------------------------ */
// //
// Security context swapping // Security context swapping
// //
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
void void
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
...@@ -1105,8 +1200,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ...@@ -1105,8 +1200,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;
...@@ -1122,8 +1215,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ...@@ -1122,8 +1215,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));
} }
...@@ -1143,8 +1234,6 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) ...@@ -1143,8 +1234,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));
} }
......
...@@ -37,6 +37,39 @@ class sp_instr; ...@@ -37,6 +37,39 @@ class sp_instr;
struct sp_cond_type; struct sp_cond_type;
struct sp_pvar; 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 class sp_head : public Sql_alloc
{ {
sp_head(const sp_head &); /* Prevent use of these */ sp_head(const sp_head &); /* Prevent use of these */
...@@ -56,6 +89,8 @@ class sp_head : public Sql_alloc ...@@ -56,6 +89,8 @@ class sp_head : public Sql_alloc
List<char *> m_calls; // Called procedures. List<char *> m_calls; // Called procedures.
List<char *> m_tables; // Used tables. List<char *> m_tables; // Used tables.
#endif #endif
LEX_STRING m_qname; // db.name
LEX_STRING m_db;
LEX_STRING m_name; LEX_STRING m_name;
LEX_STRING m_params; LEX_STRING m_params;
LEX_STRING m_retstr; // For FUNCTIONs only LEX_STRING m_retstr; // For FUNCTIONs only
...@@ -83,7 +118,7 @@ class sp_head : public Sql_alloc ...@@ -83,7 +118,7 @@ class sp_head : public Sql_alloc
// Initialize strings after parsing header // Initialize strings after parsing header
void void
init_strings(THD *thd, LEX *lex, LEX_STRING *name); init_strings(THD *thd, LEX *lex, sp_name *name);
int int
create(THD *thd); create(THD *thd);
...@@ -163,24 +198,10 @@ class sp_head : public Sql_alloc ...@@ -163,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:
...@@ -188,6 +209,7 @@ class sp_head : public Sql_alloc ...@@ -188,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
...@@ -640,8 +662,6 @@ struct st_sp_security_context ...@@ -640,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;
......
...@@ -794,6 +794,7 @@ int acl_getroot_no_password(THD *thd) ...@@ -794,6 +794,7 @@ int acl_getroot_no_password(THD *thd)
{ {
ulong user_access= NO_ACCESS; ulong user_access= NO_ACCESS;
int res= 1; int res= 1;
uint i;
ACL_USER *acl_user= 0; ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot_no_password"); DBUG_ENTER("acl_getroot_no_password");
...@@ -810,13 +811,16 @@ int acl_getroot_no_password(THD *thd) ...@@ -810,13 +811,16 @@ int acl_getroot_no_password(THD *thd)
VOID(pthread_mutex_lock(&acl_cache->lock)); VOID(pthread_mutex_lock(&acl_cache->lock));
thd->master_access= 0;
thd->db_access= 0;
/* /*
Find acl entry in user database. Find acl entry in user database.
This is specially tailored to suit the check we do for CALL of This is specially tailored to suit the check we do for CALL of
a stored procedure; thd->user is set to what is actually a a stored procedure; thd->user is set to what is actually a
priv_user, which can be ''. priv_user, which can be ''.
*/ */
for (uint i=0 ; i < acl_users.elements ; i++) for (i=0 ; i < acl_users.elements ; i++)
{ {
acl_user= dynamic_element(&acl_users,i,ACL_USER*); acl_user= dynamic_element(&acl_users,i,ACL_USER*);
if ((!acl_user->user && (!thd->user || !thd->user[0])) || if ((!acl_user->user && (!thd->user || !thd->user[0])) ||
...@@ -832,6 +836,22 @@ int acl_getroot_no_password(THD *thd) ...@@ -832,6 +836,22 @@ int acl_getroot_no_password(THD *thd)
if (acl_user) if (acl_user)
{ {
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
if (!acl_db->user ||
(thd->user && thd->user[0] && !strcmp(thd->user, acl_db->user)))
{
if (compare_hostname(&acl_db->host, thd->host, thd->ip))
{
if (!acl_db->db || (thd->db && !strcmp(acl_db->db, thd->db)))
{
thd->db_access= acl_db->access;
break;
}
}
}
}
thd->master_access= acl_user->access; thd->master_access= acl_user->access;
thd->priv_user= acl_user->user ? thd->user : (char *) ""; thd->priv_user= acl_user->user ? thd->user : (char *) "";
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include "sql_acl.h" #include "sql_acl.h"
#include "sp.h"
#include <my_dir.h> #include <my_dir.h>
#include <m_ctype.h> #include <m_ctype.h>
#ifdef __WIN__ #ifdef __WIN__
...@@ -386,6 +387,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -386,6 +387,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
} }
exit: exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
start_waiting_global_read_lock(thd); start_waiting_global_read_lock(thd);
/* /*
If this database was the client's selected database, we silently change the If this database was the client's selected database, we silently change the
......
...@@ -150,6 +150,13 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, ...@@ -150,6 +150,13 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
select= 0; select= 0;
} }
/* If quick select is used, initialize it before retrieving rows. */
if (select && select->quick && select->quick->reset())
{
delete select;
free_underlaid_joins(thd, &thd->lex->select_lex);
DBUG_RETURN(-1); // This will force out message
}
init_read_record(&info,thd,table,select,1,1); init_read_record(&info,thd,table,select,1,1);
deleted=0L; deleted=0L;
init_ftfuncs(thd, &thd->lex->select_lex, 1); init_ftfuncs(thd, &thd->lex->select_lex, 1);
......
...@@ -168,38 +168,6 @@ static int find_keyword(LEX *lex, uint len, bool function) ...@@ -168,38 +168,6 @@ static int find_keyword(LEX *lex, uint len, bool function)
lex->yylval->symbol.length=len; lex->yylval->symbol.length=len;
return symbol->tok; 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; return 0;
} }
......
...@@ -22,6 +22,7 @@ class Table_ident; ...@@ -22,6 +22,7 @@ class Table_ident;
class sql_exchange; class sql_exchange;
class LEX_COLUMN; class LEX_COLUMN;
class sp_head; class sp_head;
class sp_name;
class sp_instr; class sp_instr;
class sp_pcontext; class sp_pcontext;
...@@ -604,6 +605,7 @@ typedef struct st_lex ...@@ -604,6 +605,7 @@ typedef struct st_lex
bool derived_tables; bool derived_tables;
bool safe_to_cache_query; bool safe_to_cache_query;
sp_head *sphead; sp_head *sphead;
sp_name *spname;
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */ bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
sp_pcontext *spcont; sp_pcontext *spcont;
HASH spfuns; /* Called functions */ HASH spfuns; /* Called functions */
......
...@@ -1086,6 +1086,10 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) ...@@ -1086,6 +1086,10 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->query_length=length; thd->query_length=length;
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1); thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
thd->query[length] = '\0'; thd->query[length] = '\0';
/*
We don't need to obtain LOCK_thread_count here because in bootstrap
mode we have only one thread.
*/
thd->query_id=query_id++; thd->query_id=query_id++;
if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END)) if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
{ {
...@@ -3101,9 +3105,9 @@ mysql_execute_command(THD *thd) ...@@ -3101,9 +3105,9 @@ mysql_execute_command(THD *thd)
if (check_access(thd,INSERT_ACL,"mysql",0,1,0)) if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
break; break;
#ifdef HAVE_DLOPEN #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; goto error;
} }
if (!(res = mysql_create_function(thd,&lex->udf))) if (!(res = mysql_create_function(thd,&lex->udf)))
...@@ -3441,9 +3445,10 @@ mysql_execute_command(THD *thd) ...@@ -3441,9 +3445,10 @@ mysql_execute_command(THD *thd)
{ {
sp_head *sp; 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; goto error;
} }
else else
...@@ -3521,10 +3526,10 @@ mysql_execute_command(THD *thd) ...@@ -3521,10 +3526,10 @@ mysql_execute_command(THD *thd)
goto error; goto error;
} }
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) 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); lex->name, newname_len, &lex->sp_chistics);
else 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); lex->name, newname_len, &lex->sp_chistics);
switch (res) switch (res)
{ {
...@@ -3532,10 +3537,12 @@ mysql_execute_command(THD *thd) ...@@ -3532,10 +3537,12 @@ mysql_execute_command(THD *thd)
send_ok(thd); send_ok(thd);
break; break;
case SP_KEY_NOT_FOUND: 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; goto error;
default: 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; goto error;
} }
break; break;
...@@ -3544,19 +3551,20 @@ mysql_execute_command(THD *thd) ...@@ -3544,19 +3551,20 @@ mysql_execute_command(THD *thd)
case SQLCOM_DROP_FUNCTION: case SQLCOM_DROP_FUNCTION:
{ {
if (lex->sql_command == SQLCOM_DROP_PROCEDURE) 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 else
{ {
res= sp_drop_function(thd, lex->udf.name.str, lex->udf.name.length); res= sp_drop_function(thd, lex->spname);
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
if (res == SP_KEY_NOT_FOUND) 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 (udf)
{ {
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0)) if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0))
goto error; goto error;
if (!(res = mysql_drop_function(thd,&lex->udf.name))) if (!(res = mysql_drop_function(thd,&lex->spname->m_name)))
{ {
send_ok(thd); send_ok(thd);
break; break;
...@@ -3575,17 +3583,17 @@ mysql_execute_command(THD *thd) ...@@ -3575,17 +3583,17 @@ mysql_execute_command(THD *thd)
{ {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), 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; res= 0;
send_ok(thd); send_ok(thd);
break; break;
} }
net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex), net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),
lex->udf.name.str); lex->spname->m_name.str);
goto error; goto error;
default: default:
net_printf(thd, ER_SP_DROP_FAILED, SP_COM_STRING(lex), net_printf(thd, ER_SP_DROP_FAILED, SP_COM_STRING(lex),
lex->udf.name.str); lex->spname->m_name.str);
goto error; goto error;
} }
break; break;
...@@ -3593,16 +3601,16 @@ mysql_execute_command(THD *thd) ...@@ -3593,16 +3601,16 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_CREATE_PROC: case SQLCOM_SHOW_CREATE_PROC:
{ {
res= -1; 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; goto error;
} }
res= sp_show_create_procedure(thd, &lex->udf.name); res= sp_show_create_procedure(thd, lex->spname);
if (res != SP_OK) if (res != SP_OK)
{ /* We don't distinguish between errors for now */ { /* We don't distinguish between errors for now */
net_printf(thd, ER_SP_DOES_NOT_EXIST, 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; res= 0;
goto error; goto error;
} }
...@@ -3610,16 +3618,16 @@ mysql_execute_command(THD *thd) ...@@ -3610,16 +3618,16 @@ mysql_execute_command(THD *thd)
} }
case SQLCOM_SHOW_CREATE_FUNC: 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; goto error;
} }
res= sp_show_create_function(thd, &lex->udf.name); res= sp_show_create_function(thd, lex->spname);
if (res != SP_OK) if (res != SP_OK)
{ /* We don't distinguish between errors for now */ { /* We don't distinguish between errors for now */
net_printf(thd, ER_SP_DOES_NOT_EXIST, 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; res= 0;
goto error; goto error;
} }
......
...@@ -246,7 +246,11 @@ int mysql_update(THD *thd, ...@@ -246,7 +246,11 @@ int mysql_update(THD *thd,
DISK_BUFFER_SIZE, MYF(MY_WME))) DISK_BUFFER_SIZE, MYF(MY_WME)))
goto err; goto err;
/* If quick select is used, initialize it before retrieving rows. */
if (select && select->quick && select->quick->reset())
goto err;
init_read_record(&info,thd,table,select,0,1); init_read_record(&info,thd,table,select,0,1);
thd->proc_info="Searching rows for update"; thd->proc_info="Searching rows for update";
uint tmp_limit= limit; uint tmp_limit= limit;
......
...@@ -92,6 +92,7 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B) ...@@ -92,6 +92,7 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B)
chooser_compare_func_creator boolfunc2creator; chooser_compare_func_creator boolfunc2creator;
struct sp_cond_type *spcondtype; struct sp_cond_type *spcondtype;
struct { int vars, conds, hndlrs, curs; } spblock; struct { int vars, conds, hndlrs, curs; } spblock;
sp_name *spname;
struct st_lex *lex; struct st_lex *lex;
} }
...@@ -568,17 +569,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -568,17 +569,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SECOND_SYM %token SECOND_SYM
%token SECOND_MICROSECOND_SYM %token SECOND_MICROSECOND_SYM
%token SHARE_SYM %token SHARE_SYM
%token SP_FUNC
%token SUBDATE_SYM %token SUBDATE_SYM
%token SUBSTRING %token SUBSTRING
%token SUBSTRING_INDEX %token SUBSTRING_INDEX
%token TRIM %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 UNIQUE_USERS
%token UNIX_TIMESTAMP %token UNIX_TIMESTAMP
%token USER %token USER
...@@ -640,7 +634,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -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 LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component key_cache_name NCHAR_STRING opt_component key_cache_name
SP_FUNC ident_or_spfunc sp_opt_label sp_opt_label
%type <lex_str_ptr> %type <lex_str_ptr>
opt_table_alias opt_table_alias
...@@ -683,7 +677,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -683,7 +677,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
simple_ident_nospvar simple_ident_q simple_ident_nospvar simple_ident_q
%type <item_list> %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 ident_list ident_list_arg
%type <key_type> %type <key_type>
...@@ -701,10 +695,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -701,10 +695,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <table_list> %type <table_list>
join_table_list join_table 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 <date_time_type> date_time_type;
%type <interval> interval %type <interval> interval
...@@ -782,6 +772,7 @@ END_OF_INPUT ...@@ -782,6 +772,7 @@ END_OF_INPUT
%type <spcondtype> sp_cond sp_hcond %type <spcondtype> sp_cond sp_hcond
%type <spblock> sp_decls sp_decl %type <spblock> sp_decls sp_decl
%type <lex> sp_cursor_stmt %type <lex> sp_cursor_stmt
%type <spname> sp_name
%type <NONE> %type <NONE>
'-' '+' '*' '/' '%' '(' ')' '-' '+' '*' '/' '%' '(' ')'
...@@ -1030,15 +1021,15 @@ create: ...@@ -1030,15 +1021,15 @@ create:
lex->name=$4.str; lex->name=$4.str;
lex->create_info.options=$3; 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 *lex=Lex;
lex->udf.name = $4; lex->spname= $4;
lex->udf.type= $2; lex->udf.type= $2;
} }
create_function_tail create_function_tail
{} {}
| CREATE PROCEDURE ident | CREATE PROCEDURE sp_name
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp; sp_head *sp;
...@@ -1089,7 +1080,7 @@ create: ...@@ -1089,7 +1080,7 @@ create:
{ {
LEX *lex= Lex; LEX *lex= Lex;
lex->sphead->init_strings(YYTHD, lex, &$3); lex->sphead->init_strings(YYTHD, lex, $3);
lex->sql_command= SQLCOM_CREATE_PROCEDURE; lex->sql_command= SQLCOM_CREATE_PROCEDURE;
/* Restore flag if it was cleared above */ /* Restore flag if it was cleared above */
if (lex->sphead->m_old_cmq) if (lex->sphead->m_old_cmq)
...@@ -1098,9 +1089,16 @@ create: ...@@ -1098,9 +1089,16 @@ create:
} }
; ;
ident_or_spfunc: sp_name:
IDENT_sys { $$= $1; } IDENT_sys '.' IDENT_sys
| SP_FUNC { $$= $1; } {
$$= new sp_name($1, $3);
$$->init_qname(YYTHD);
}
| IDENT_sys
{
$$= sp_name_current_db_new(YYTHD, $1);
}
; ;
create_function_tail: create_function_tail:
...@@ -1108,6 +1106,7 @@ create_function_tail: ...@@ -1108,6 +1106,7 @@ create_function_tail:
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command = SQLCOM_CREATE_FUNCTION; lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = lex->spname->m_name;
lex->udf.returns=(Item_result) $2; lex->udf.returns=(Item_result) $2;
lex->udf.dl=$4.str; lex->udf.dl=$4.str;
} }
...@@ -1169,7 +1168,7 @@ create_function_tail: ...@@ -1169,7 +1168,7 @@ create_function_tail:
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION; 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 */ /* Restore flag if it was cleared above */
if (sp->m_old_cmq) if (sp->m_old_cmq)
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
...@@ -1219,12 +1218,12 @@ sp_suid: ...@@ -1219,12 +1218,12 @@ sp_suid:
; ;
call: call:
CALL_SYM ident_or_spfunc CALL_SYM sp_name
{ {
LEX *lex = Lex; LEX *lex = Lex;
lex->sql_command= SQLCOM_CALL; lex->sql_command= SQLCOM_CALL;
lex->udf.name= $2; lex->spname= $2;
lex->value_list.empty(); lex->value_list.empty();
} }
'(' sp_cparam_list ')' {} '(' sp_cparam_list ')' {}
...@@ -1584,6 +1583,11 @@ sp_proc_stmt: ...@@ -1584,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.)
...@@ -2739,7 +2743,7 @@ alter: ...@@ -2739,7 +2743,7 @@ alter:
lex->sql_command=SQLCOM_ALTER_DB; lex->sql_command=SQLCOM_ALTER_DB;
lex->name=$3.str; lex->name=$3.str;
} }
| ALTER PROCEDURE ident | ALTER PROCEDURE sp_name
{ {
LEX *lex= Lex; LEX *lex= Lex;
...@@ -2752,9 +2756,9 @@ alter: ...@@ -2752,9 +2756,9 @@ alter:
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command= SQLCOM_ALTER_PROCEDURE; 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; LEX *lex= Lex;
...@@ -2767,7 +2771,7 @@ alter: ...@@ -2767,7 +2771,7 @@ alter:
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->sql_command= SQLCOM_ALTER_FUNCTION;
lex->udf.name= $3; lex->spname= $3;
} }
; ;
...@@ -3919,55 +3923,89 @@ simple_expr: ...@@ -3919,55 +3923,89 @@ simple_expr:
{ $$= new Item_func_round($3,$5,1); } { $$= new Item_func_round($3,$5,1); }
| TRUE_SYM | TRUE_SYM
{ $$= new Item_int((char*) "TRUE",1,1); } { $$= new Item_int((char*) "TRUE",1,1); }
| SP_FUNC '(' sp_expr_list ')' | ident '.' ident '(' udf_expr_list ')'
{ {
sp_add_fun_to_lex(Lex, $1); LEX *lex= Lex;
if ($3) sp_name *name= new sp_name($1, $3);
$$= new Item_func_sp($1, *$3);
name->init_qname(YYTHD);
sp_add_fun_to_lex(Lex, name);
if ($5)
$$= new Item_func_sp(name, *$5);
else else
$$= new Item_func_sp($1); $$= new Item_func_sp(name);
} }
| UDA_CHAR_SUM '(' udf_expr_list ')' | IDENT_sys '(' udf_expr_list ')'
{
#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) if ($3 != NULL)
$$ = new Item_sum_udf_str($1, *$3); $$ = new Item_func_udf_str(udf, *$3);
else else
$$ = new Item_sum_udf_str($1); $$ = new Item_func_udf_str(udf);
} }
| UDA_FLOAT_SUM '(' udf_expr_list ')' else
{ {
if ($3 != NULL) if ($3 != NULL)
$$ = new Item_sum_udf_float($1, *$3); $$ = new Item_sum_udf_str(udf, *$3);
else else
$$ = new Item_sum_udf_float($1); $$ = new Item_sum_udf_str(udf);
} }
| UDA_INT_SUM '(' udf_expr_list ')' break;
case REAL_RESULT:
if (udf->type == UDFTYPE_FUNCTION)
{ {
if ($3 != NULL) if ($3 != NULL)
$$ = new Item_sum_udf_int($1, *$3); $$ = new Item_func_udf_float(udf, *$3);
else else
$$ = new Item_sum_udf_int($1); $$ = new Item_func_udf_float(udf);
} }
| UDF_CHAR_FUNC '(' udf_expr_list ')' else
{ {
if ($3 != NULL) if ($3 != NULL)
$$ = new Item_func_udf_str($1, *$3); $$ = new Item_sum_udf_float(udf, *$3);
else else
$$ = new Item_func_udf_str($1); $$ = new Item_sum_udf_float(udf);
} }
| UDF_FLOAT_FUNC '(' udf_expr_list ')' break;
case INT_RESULT:
if (udf->type == UDFTYPE_FUNCTION)
{ {
if ($3 != NULL) if ($3 != NULL)
$$ = new Item_func_udf_float($1, *$3); $$ = new Item_func_udf_int(udf, *$3);
else else
$$ = new Item_func_udf_float($1); $$ = new Item_func_udf_int(udf);
} }
| UDF_INT_FUNC '(' udf_expr_list ')' else
{ {
if ($3 != NULL) if ($3 != NULL)
$$ = new Item_func_udf_int($1, *$3); $$ = new Item_sum_udf_int(udf, *$3);
else else
$$ = new Item_func_udf_int($1); $$ = new Item_sum_udf_int(udf);
}
break;
default:
YYABORT;
}
}
else
#endif /* HAVE_DLOPEN */
{
sp_name *name= sp_name_current_db_new(YYTHD, $1);
sp_add_fun_to_lex(Lex, name);
if ($3)
$$= new Item_func_sp(name, *$3);
else
$$= new Item_func_sp(name);
}
} }
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')' | UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
{ {
...@@ -4075,10 +4113,6 @@ fulltext_options: ...@@ -4075,10 +4113,6 @@ fulltext_options:
| IN_SYM BOOLEAN_SYM MODE_SYM { $$= FT_BOOL; } | IN_SYM BOOLEAN_SYM MODE_SYM { $$= FT_BOOL; }
; ;
sp_expr_list:
/* empty */ { $$= NULL; }
| expr_list { $$= $1;};
udf_expr_list: udf_expr_list:
/* empty */ { $$= NULL; } /* empty */ { $$= NULL; }
| udf_expr_list2 { $$= $1;} | udf_expr_list2 { $$= $1;}
...@@ -4825,19 +4859,19 @@ drop: ...@@ -4825,19 +4859,19 @@ drop:
lex->drop_if_exists=$3; lex->drop_if_exists=$3;
lex->name=$4.str; 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 *lex=Lex;
lex->sql_command = SQLCOM_DROP_FUNCTION; lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->drop_if_exists= $3; 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 *lex=Lex;
lex->sql_command = SQLCOM_DROP_PROCEDURE; lex->sql_command = SQLCOM_DROP_PROCEDURE;
lex->drop_if_exists= $3; lex->drop_if_exists= $3;
lex->udf.name= $4; lex->spname= $4;
} }
| DROP USER | DROP USER
{ {
...@@ -5316,15 +5350,19 @@ show_param: ...@@ -5316,15 +5350,19 @@ show_param:
{ {
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
} }
| CREATE PROCEDURE ident | CREATE PROCEDURE sp_name
{ {
Lex->sql_command = SQLCOM_SHOW_CREATE_PROC; LEX *lex= Lex;
Lex->udf.name= $3;
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 *lex= Lex;
Lex->udf.name= $3;
lex->sql_command = SQLCOM_SHOW_CREATE_FUNC;
lex->spname= $3;
} }
| PROCEDURE STATUS_SYM wild | PROCEDURE STATUS_SYM wild
{ {
......
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