Commit 0dcc255b authored by igor@rurik.mysql.com's avatar igor@rurik.mysql.com

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

into rurik.mysql.com:/home/igor/dev/mysql-5.0-0
parents bae25543 5954e94f
......@@ -24,6 +24,7 @@ bk@admin.bk
bk@mysql.r18.ru
carsten@tsort.bitbybit.dk
davida@isil.mysql.com
dlenev@brandersnatch.localdomain
dlenev@build.mysql.com
dlenev@mysql.com
gerberb@ou800.zenez.com
......
......@@ -1057,9 +1057,9 @@
CREATE TABLE proc (
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,
specific_name char(64) binary DEFAULT '' NOT NULL,
specific_name char(64) DEFAULT '' NOT NULL,
language enum('SQL') DEFAULT 'SQL' NOT NULL,
sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL,
is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,
......
......@@ -339,4 +339,5 @@
#define ER_SP_DUP_CURS 1320
#define ER_SP_CANT_ALTER 1321
#define ER_SP_SUBSELECT_NYI 1322
#define ER_ERROR_MESSAGES 323
#define ER_SP_NO_USE 1323
#define ER_ERROR_MESSAGES 324
......@@ -196,3 +196,4 @@ ER_SP_DUP_COND, "42000", "",
ER_SP_DUP_CURS, "42000", "",
/*ER_SP_CANT_ALTER*/
ER_SP_SUBSELECT_NYI, "0A000", "",
ER_SP_NO_USE, "42000", "",
......@@ -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
12 12 12 12 12 12 12 1012 12 12 12 12
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;
......@@ -144,7 +144,6 @@ insert into t1 values (1);
show open tables;
Database Table In_use Name_locked
test t1 0 0
mysql proc 0 0
drop table t1;
create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" ENGINE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed;
show create table t1;
......
......@@ -251,6 +251,10 @@ declare c cursor for select * from t1;
declare c cursor for select field from t1;
end|
ERROR 42000: Duplicate cursor: c
create procedure u()
use sptmp;
#|
ERROR 42000: USE is not allowed in a stored procedure
create procedure bug1965()
begin
declare c cursor for select val from t1 order by valname;
......
use test;
grant usage on *.* to dummy@localhost;
grant usage on *.* to user1@localhost;
flush privileges;
drop database if exists db1_secret;
create database db1_secret;
use db1_secret;
......@@ -7,39 +8,104 @@ create table t1 ( u varchar(64), i int );
create procedure stamp(i int)
insert into db1_secret.t1 values (user(), i);
show procedure status like 'stamp';
Name Type Definer Modified Created Security_type Comment
stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
Db Name Type Definer Modified Created Security_type Comment
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
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);
select * from t1;
u i
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;
ERROR 42000: Access denied for user: 'dummy'@'localhost' to database 'db1_secret'
call stamp(3);
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
call db1_secret.stamp(3);
select db1_secret.db();
db1_secret.db()
db1_secret
select * from db1_secret.t1;
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
select * from t1;
u i
root@localhost 1
dummy@localhost 2
user1@localhost 2
anon@localhost 3
alter procedure stamp sql security invoker;
show procedure status like 'stamp';
Name Type Definer Modified Created Security_type Comment
stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
Db Name Type Definer Modified Created Security_type Comment
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
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);
select * from t1;
u i
root@localhost 1
dummy@localhost 2
user1@localhost 2
anon@localhost 3
root@localhost 4
call stamp(5);
ERROR 42000: Access denied for user: 'dummy'@'localhost' to database 'db1_secret'
call stamp(6);
select db();
db()
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'
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;
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;
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
foo 42
delete from t1;
drop procedure foo42;
create procedure u()
use sptmp;
drop database if exists sptmp;
create database sptmp;
use test;
call u();
select database();
database()
test
drop database sptmp;
drop procedure u;
create procedure bar(x char(16), y int)
insert into test.t1 values (x, y);
call bar("bar", 666);
......@@ -746,7 +735,7 @@ delete from t1|
alter procedure chistics sql security invoker name chistics2|
show create procedure chistics2|
Procedure Create Procedure
chistics2 CREATE PROCEDURE `chistics2`()
chistics2 CREATE PROCEDURE `test`.`chistics2`()
SQL SECURITY INVOKER
COMMENT 'Characteristics procedure test'
insert into t1 values ("chistics", 1)
......@@ -763,7 +752,7 @@ chistics()
alter function chistics name chistics2 comment 'Characteristics function test'|
show create function chistics2|
Function Create Function
chistics2 CREATE FUNCTION `chistics2`() RETURNS int
chistics2 CREATE FUNCTION `test`.`chistics2`() RETURNS int
DETERMINISTIC
SQL SECURITY INVOKER
COMMENT 'Characteristics function test'
......@@ -797,6 +786,22 @@ select @c1, @c2|
12 3
delete from t1|
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)
begin
declare n int;
......@@ -939,23 +944,23 @@ begin
show create function fac;
end|
call bug2267_1()|
Name Type Definer Modified Created Security_type Comment
bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
Db Name Type Definer Modified Created Security_type Comment
test bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
test bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
test bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
test bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call bug2267_2()|
Name Type Definer Modified Created Security_type Comment
fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
Db Name Type Definer Modified Created Security_type Comment
test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call bug2267_3()|
Procedure Create Procedure
bug2267_1 CREATE PROCEDURE `bug2267_1`()
bug2267_1 CREATE PROCEDURE `test`.`bug2267_1`()
begin
show procedure status;
end
call bug2267_4()|
Function Create Function
fac CREATE FUNCTION `fac`(n int unsigned) RETURNS bigint unsigned
fac CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint unsigned
begin
declare f bigint unsigned default 1;
while n > 1 do
......@@ -989,6 +994,24 @@ call bug2614()|
call bug2614()|
drop table t3|
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|
create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned)
......@@ -1029,12 +1052,12 @@ n f
20 2432902008176640000
drop table fac|
show function status like '%f%'|
Name Type Definer Modified Created Security_type Comment
fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
Db Name Type Definer Modified Created Security_type Comment
test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
drop procedure ifac|
drop function fac|
show function status like '%f%'|
Name Type Definer Modified Created Security_type Comment
Db Name Type Definer Modified Created Security_type Comment
drop table if exists primes|
create table primes (
i int unsigned not null primary key,
......@@ -1095,7 +1118,7 @@ end while;
end|
show create procedure opp|
Procedure Create Procedure
opp CREATE PROCEDURE `opp`(n bigint unsigned, out pp bool)
opp CREATE PROCEDURE `test`.`opp`(n bigint unsigned, out pp bool)
begin
declare r double;
declare b, s bigint unsigned default 0;
......@@ -1122,9 +1145,9 @@ end if;
end loop;
end
show procedure status like '%p%'|
Name Type Definer Modified Created Security_type Comment
ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
Db Name Type Definer Modified Created Security_type Comment
test ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
test opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call ip(200)|
select * from primes where i=45 or i=100 or i=199|
i p
......@@ -1135,7 +1158,7 @@ drop table primes|
drop procedure opp|
drop procedure ip|
show procedure status like '%p%'|
Name Type Definer Modified Created Security_type Comment
Db Name Type Definer Modified Created Security_type Comment
drop table if exists fib|
create table fib ( f bigint unsigned not null )|
insert into fib values (1), (1)|
......@@ -1185,19 +1208,19 @@ create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker
insert into test.t1 values (x, y)|
show procedure status like 'bar'|
Name Type Definer Modified Created Security_type Comment
bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER 111111111111
Db Name Type Definer Modified Created Security_type Comment
test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER 111111111111
alter procedure bar name bar2 comment "2222222222" sql security definer|
alter procedure bar2 name bar comment "3333333333"|
alter procedure bar|
show create procedure bar|
Procedure Create Procedure
bar CREATE PROCEDURE `bar`(x char(16), y int)
bar CREATE PROCEDURE `test`.`bar`(x char(16), y int)
COMMENT '3333333333'
insert into test.t1 values (x, y)
show procedure status like 'bar'|
Name Type Definer Modified Created Security_type Comment
bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333
Db Name Type Definer Modified Created Security_type Comment
test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333
drop procedure bar|
drop table t1;
drop table t2;
......@@ -14,6 +14,6 @@ update t1 set n = 3;
unlock tables;
show status like 'Table_lock%';
Variable_name Value
Table_locks_immediate 4
Table_locks_immediate 3
Table_locks_waited 1
drop table t1;
......@@ -267,5 +267,15 @@ select * from t3 where
key5=5 or key6=6 or key7=7 or key8=8 or
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;
......@@ -330,6 +330,12 @@ begin
declare c cursor for select field from t1;
end|
# USE is not allowed
--error 1323
create procedure u()
use sptmp;
#
# BUG#1965
#
......
......@@ -7,8 +7,9 @@ connect (con1root,localhost,root,,);
connection con1root;
use test;
# Create dummy user with no particular access rights
grant usage on *.* to dummy@localhost;
# Create user user1 with no particular access rights
grant usage on *.* to user1@localhost;
flush privileges;
--disable_warnings
drop database if exists db1_secret;
......@@ -20,26 +21,32 @@ use db1_secret;
create table t1 ( u varchar(64), i int );
# Our test procedure
# A test procedure and function
create procedure stamp(i int)
insert into db1_secret.t1 values (user(), i);
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like 'stamp';
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
call stamp(1);
select * from t1;
select db();
connect (con2dummy,localhost,dummy,,);
connect (con2user1,localhost,user1,,);
connect (con3anon,localhost,anon,,);
#
# Dummy can
# User1 can
#
connection con2dummy;
connection con2user1;
# This should work...
call stamp(2);
call db1_secret.stamp(2);
select db1_secret.db();
# ...but not this
--error 1044
......@@ -51,7 +58,8 @@ select * from db1_secret.t1;
connection con3anon;
# This should work...
call stamp(3);
call db1_secret.stamp(3);
select db1_secret.db();
# ...but not this
--error 1044
......@@ -67,21 +75,28 @@ select * from t1;
# Change to invoker's rights
#
alter procedure stamp sql security invoker;
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like 'stamp';
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
call stamp(4);
select * from t1;
select db();
#
# Dummy cannot
# User1 cannot
#
connection con2dummy;
connection con2user1;
# This should not work
--error 1044
call stamp(5);
call db1_secret.stamp(5);
--error 1044
select db1_secret.db();
#
# Anonymous cannot
......@@ -90,11 +105,69 @@ connection con3anon;
# This should not work
--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
connection con1root;
drop procedure stamp;
use test;
select type,db,name from mysql.proc;
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;
drop procedure foo42;
# USE test: Make sure we remain in the same DB.
create procedure u()
use sptmp;
--disable_warnings
drop database if exists sptmp;
--enable_warnings
create database sptmp;
use test;
call u();
select database();
drop database sptmp;
drop procedure u;
# Single statement, two IN params.
create procedure bar(x char(16), y int)
insert into test.t1 values (x, y);
......@@ -920,6 +905,32 @@ delete from t1|
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
#
......@@ -1094,9 +1105,9 @@ begin
show create function fac;
end|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
call bug2267_1()|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
call bug2267_2()|
call bug2267_3()|
call bug2267_4()|
......@@ -1138,6 +1149,35 @@ call bug2614()|
drop table t3|
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
......@@ -1168,11 +1208,11 @@ end|
call ifac(20)|
select * from fac|
drop table fac|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show function status like '%f%'|
drop procedure ifac|
drop function fac|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show function status like '%f%'|
......@@ -1249,7 +1289,7 @@ begin
end while;
end|
show create procedure opp|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like '%p%'|
# This isn't the fastest way in the world to compute prime numbers, so
......@@ -1261,7 +1301,7 @@ select * from primes where i=45 or i=100 or i=199|
drop table primes|
drop procedure opp|
drop procedure ip|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like '%p%'|
......@@ -1308,13 +1348,13 @@ drop procedure fib|
create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker
insert into test.t1 values (x, y)|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like 'bar'|
alter procedure bar name bar2 comment "2222222222" sql security definer|
alter procedure bar2 name bar comment "3333333333"|
alter procedure bar|
show create procedure bar|
--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00'
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like 'bar'|
drop procedure bar|
delimiter ;|
......
......@@ -290,9 +290,9 @@ if test ! -f $mdata/proc.frm
then
c_p="$c_p CREATE TABLE proc ("
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 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 sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL,"
c_p="$c_p is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,"
......
......@@ -141,9 +141,9 @@ unique index (name)
CREATE TABLE IF NOT EXISTS proc (
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,
specific_name char(64) binary DEFAULT '' NOT NULL,
specific_name char(64) DEFAULT '' NOT NULL,
language enum('SQL') DEFAULT 'SQL' NOT NULL,
sql_data_access enum('CONTAINS_SQL') DEFAULT 'CONTAINS_SQL' NOT NULL,
is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,
......@@ -179,3 +179,7 @@ CREATE TABLE IF NOT EXISTS proc (
comment char(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (db,name,type)
) 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()
return ull->thread_id;
}
Item_func_sp::Item_func_sp(sp_name *name)
:Item_func(), m_name(name), m_sp(NULL)
{
m_name->init_qname(current_thd);
}
Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list)
:Item_func(list), m_name(name), m_sp(NULL)
{
m_name->init_qname(current_thd);
}
const char *
Item_func_sp::func_name() const
{
return m_name->m_name.str;
}
int
Item_func_sp::execute(Item **itp)
{
......@@ -3138,9 +3157,13 @@ Item_func_sp::execute(Item **itp)
#endif
if (! m_sp)
m_sp= sp_find_function(thd, &m_name);
m_sp= sp_find_function(thd, m_name);
if (! m_sp)
{
my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
"FUNCTION", m_name->m_qname);
DBUG_RETURN(-1);
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
sp_change_security_context(thd, m_sp, &save_ctx);
......@@ -3161,12 +3184,14 @@ Item_func_sp::field_type() const
DBUG_ENTER("Item_func_sp::field_type");
if (! m_sp)
m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name));
m_sp= sp_find_function(current_thd, m_name);
if (m_sp)
{
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
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);
}
......@@ -3177,11 +3202,13 @@ Item_func_sp::result_type() const
DBUG_PRINT("info", ("m_sp = %p", m_sp));
if (! m_sp)
m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name));
m_sp= sp_find_function(current_thd, m_name);
if (m_sp)
{
DBUG_RETURN(m_sp->result());
}
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);
}
......@@ -3191,8 +3218,13 @@ Item_func_sp::fix_length_and_dec()
DBUG_ENTER("Item_func_sp::fix_length_and_dec");
if (! m_sp)
m_sp= sp_find_function(current_thd, &m_name);
if (m_sp)
m_sp= sp_find_function(current_thd, m_name);
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()) {
case STRING_RESULT:
......
......@@ -1075,32 +1075,26 @@ enum Cast_target
*/
class sp_head;
class sp_name;
class Item_func_sp :public Item_func
{
private:
LEX_STRING m_name;
sp_name *m_name;
mutable sp_head *m_sp;
int execute(Item **itp);
public:
Item_func_sp(LEX_STRING name)
:Item_func(), m_name(name), m_sp(NULL)
{}
Item_func_sp(sp_name *name);
Item_func_sp(LEX_STRING name, List<Item> &list)
:Item_func(list), m_name(name), m_sp(NULL)
{}
Item_func_sp(sp_name *name, List<Item> &list);
virtual ~Item_func_sp()
{}
const char *func_name() const
{
return m_name.str;
}
const char *func_name() const;
enum enum_field_types field_type() const;
......@@ -1116,7 +1110,10 @@ class Item_func_sp :public Item_func
Item *it;
if (execute(&it))
{
null_value= 1;
return 0.0;
}
return it->val();
}
......@@ -1125,7 +1122,10 @@ class Item_func_sp :public Item_func
Item *it;
if (execute(&it))
{
null_value= 1;
return NULL;
}
return it->val_str(str);
}
......
......@@ -87,7 +87,16 @@ class QUICK_SELECT_I
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;
/*
Call reset() before first get_next call. get_next must not be called if
reset() call fails.
*/
virtual int reset(void) = 0;
virtual int get_next() = 0; /* get next record to retrieve */
virtual bool reverse_sorted() = 0;
......
......@@ -335,3 +335,4 @@ character-set=latin2
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -329,3 +329,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -337,3 +337,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -331,3 +331,4 @@ character-set=latin7
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -338,3 +338,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -326,3 +326,4 @@ character-set=greek
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -328,3 +328,4 @@ character-set=latin2
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -328,3 +328,4 @@ character-set=ujis
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -326,3 +326,4 @@ character-set=euckr
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -328,3 +328,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -328,3 +328,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -330,3 +330,4 @@ character-set=latin2
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -327,3 +327,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -330,3 +330,4 @@ character-set=latin2
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -328,3 +328,4 @@ character-set=koi8r
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -321,3 +321,4 @@ character-set=cp1250
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -334,3 +334,4 @@ character-set=latin2
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -328,3 +328,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -326,3 +326,4 @@ character-set=latin1
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
......@@ -331,3 +331,4 @@ character-set=koi8u
"Duplicate cursor: %s"
"Failed to ALTER %s %s"
"Subselect value not supported"
"USE is not allowed in a stored procedure"
This diff is collapsed.
......@@ -28,59 +28,77 @@
#define SP_PARSE_ERROR -6
#define SP_INTERNAL_ERROR -7
/* Drop all routines in database 'db' */
int
sp_drop_db_routines(THD *thd, char *db);
sp_head *
sp_find_procedure(THD *thd, LEX_STRING *name);
sp_find_procedure(THD *thd, sp_name *name);
int
sp_create_procedure(THD *thd, sp_head *sp);
int
sp_drop_procedure(THD *thd, char *name, uint namelen);
sp_drop_procedure(THD *thd, sp_name *name);
int
sp_update_procedure(THD *thd, char *name, uint namelen,
sp_update_procedure(THD *thd, sp_name *name,
char *newname, uint newnamelen,
st_sp_chistics *chistics);
int
sp_show_create_procedure(THD *thd, LEX_STRING *name);
sp_show_create_procedure(THD *thd, sp_name *name);
int
sp_show_status_procedure(THD *thd, const char *wild);
sp_head *
sp_find_function(THD *thd, LEX_STRING *name);
sp_find_function(THD *thd, sp_name *name);
int
sp_create_function(THD *thd, sp_head *sp);
int
sp_drop_function(THD *thd, char *name, uint namelen);
sp_drop_function(THD *thd, sp_name *name);
int
sp_update_function(THD *thd, char *name, uint namelen,
sp_update_function(THD *thd, sp_name *name,
char *newname, uint newnamelen,
st_sp_chistics *chistics);
int
sp_show_create_function(THD *thd, LEX_STRING *name);
sp_show_create_function(THD *thd, sp_name *name);
int
sp_show_status_function(THD *thd, const char *wild);
// QQ Temporary until the function call detection in sql_lex has been reworked.
bool
sp_function_exists(THD *thd, LEX_STRING *name);
sp_function_exists(THD *thd, sp_name *name);
// This is needed since we have to read the functions before we
// do anything else.
void
sp_add_fun_to_lex(LEX *lex, LEX_STRING fun);
sp_add_fun_to_lex(LEX *lex, sp_name *fun);
void
sp_merge_funs(LEX *dst, LEX *src);
int
sp_cache_functions(THD *thd, LEX *lex);
//
// Utilities...
//
// Do a "use newdb". The current db is stored at olddb.
// If newdb is the same as the current one, nothing is changed.
int
sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax,
bool no_access_check);
// Like mysql_change_db() but handles empty db name and the send_ok() problem.
int
sp_change_db(THD *thd, char *db, bool no_access_check);
#endif /* _SP_H_ */
......@@ -71,7 +71,7 @@ sp_cache_insert(sp_cache **cp, sp_head *sp)
}
sp_head *
sp_cache_lookup(sp_cache **cp, char *name, uint namelen)
sp_cache_lookup(sp_cache **cp, sp_name *name)
{
ulong v;
sp_cache *c= *cp;
......@@ -89,11 +89,11 @@ sp_cache_lookup(sp_cache **cp, char *name, uint namelen)
c->version= v;
return NULL;
}
return c->lookup(name, namelen);
return c->lookup(name->m_qname.str, name->m_qname.length);
}
bool
sp_cache_remove(sp_cache **cp, char *name, uint namelen)
sp_cache_remove(sp_cache **cp, sp_name *name)
{
sp_cache *c= *cp;
bool found= FALSE;
......@@ -109,18 +109,28 @@ sp_cache_remove(sp_cache **cp, char *name, uint namelen)
if (c->version < v)
c->remove_all();
else
found= c->remove(name, namelen);
found= c->remove(name->m_qname.str, name->m_qname.length);
c->version= v+1;
}
return found;
}
void
sp_cache_invalidate()
{
pthread_mutex_lock(&Cversion_lock); // LOCK
Cversion++;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
}
static byte *
hash_get_key_for_sp_head(const byte *ptr, uint *plen,
my_bool first)
{
return (byte*) ((sp_head*)ptr)->name(plen);
sp_head *sp= (sp_head *)ptr;
*plen= sp->m_qname.length;
return (byte*) sp->m_qname.str;
}
static void
......
......@@ -35,10 +35,13 @@ void sp_cache_clear(sp_cache **cp);
void sp_cache_insert(sp_cache **cp, sp_head *sp);
/* Lookup an SP in cache */
sp_head *sp_cache_lookup(sp_cache **cp, char *name, uint namelen);
sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
/* Remove an SP from cache. Returns true if something was removed */
bool sp_cache_remove(sp_cache **cp, char *name, uint namelen);
bool sp_cache_remove(sp_cache **cp, sp_name *name);
/* Invalidate a cache */
void sp_cache_invalidate();
/*
......
......@@ -130,6 +130,52 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
DBUG_RETURN(it);
}
/*
*
* sp_name
*
*/
void
sp_name::init_qname(THD *thd)
{
m_qname.length= m_db.length+m_name.length+1;
m_qname.str= alloc_root(&thd->mem_root, m_qname.length+1);
sprintf(m_qname.str, "%*s.%*s",
m_db.length, (m_db.length ? m_db.str : ""),
m_name.length, m_name.str);
}
sp_name *
sp_name_current_db_new(THD *thd, LEX_STRING name)
{
sp_name *qname;
if (! thd->db)
qname= new sp_name(name);
else
{
LEX_STRING db;
db.length= strlen(thd->db);
db.str= thd->strmake(thd->db, db.length);
qname= new sp_name(db, name);
}
qname->init_qname(thd);
return qname;
}
/* ------------------------------------------------------------------ */
/*
*
* sp_head
*
*/
void *
sp_head::operator new(size_t size)
{
......@@ -178,22 +224,42 @@ sp_head::init(LEX *lex)
lex->spcont= m_pcont= new sp_pcontext();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
m_param_begin= m_param_end= m_returns_begin= m_returns_end= m_body_begin= 0;
m_name.str= m_params.str= m_retstr.str= m_body.str= m_defstr.str= 0;
m_name.length= m_params.length= m_retstr.length= m_body.length=
m_defstr.length= 0;
m_qname.str= m_db.str= m_name.str= m_params.str= m_retstr.str=
m_body.str= m_defstr.str= 0;
m_qname.length= m_db.length= m_name.length= m_params.length=
m_retstr.length= m_body.length= m_defstr.length= 0;
DBUG_VOID_RETURN;
}
void
sp_head::init_strings(THD *thd, LEX *lex, LEX_STRING *name)
sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
{
DBUG_ENTER("sp_head::init_strings");
/* During parsing, we must use thd->mem_root */
MEM_ROOT *root= &thd->mem_root;
DBUG_PRINT("info", ("name: %*s", name->length, name->str));
m_name.length= name->length;
m_name.str= strmake_root(root, name->str, name->length);
DBUG_PRINT("info", ("name: %*.s%*s",
name->m_db.length, name->m_db.str,
name->m_name.length, name->m_name.str));
/* We have to copy strings to get them into the right memroot */
if (name->m_db.length == 0)
{
m_db.length= (thd->db ? strlen(thd->db) : 0);
m_db.str= strmake_root(root, (thd->db ? thd->db : ""), m_db.length);
}
else
{
m_db.length= name->m_db.length;
m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
}
m_name.length= name->m_name.length;
m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
if (name->m_qname.length == 0)
name->init_qname(thd);
m_qname.length= name->m_qname.length;
m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
m_params.length= m_param_end- m_param_begin;
m_params.str= strmake_root(root,
(char *)m_param_begin, m_params.length);
......@@ -271,30 +337,22 @@ int
sp_head::execute(THD *thd)
{
DBUG_ENTER("sp_head::execute");
char olddbname[128];
char *olddbptr= thd->db;
char olddb[128];
char *olddbptr;
sp_rcontext *ctx= thd->spcont;
int ret= 0;
uint ip= 0;
#ifndef EMBEDDED_LIBRARY
if (check_stack_overrun(thd, olddbptr))
if (check_stack_overrun(thd, olddb))
{
DBUG_RETURN(-1);
}
#endif
if (olddbptr)
{
uint i= 0;
char *p= olddbptr;
/* Fast inline strncpy without padding... */
while (*p && i < sizeof(olddbname))
olddbname[i++]= *p++;
if (i == sizeof(olddbname))
i-= 1; // QQ Error or warning for truncate?
olddbname[i]= '\0';
}
olddbptr= thd->db;
if ((ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0)))
goto done;
if (ctx)
ctx->clear_handler();
......@@ -331,20 +389,20 @@ sp_head::execute(THD *thd)
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",
ret, thd->killed, thd->query_error));
if (thd->killed || thd->query_error)
if (thd->killed || thd->query_error || thd->net.report_error)
ret= -1;
/* If the DB has changed, the pointer has changed too, but the
original thd->db will then have been freed */
if (olddbptr && olddbptr != thd->db)
if (olddbptr != thd->db)
{
/* QQ Maybe we should issue some special error message or warning here,
if this fails?? */
if (! thd->killed)
ret= mysql_change_db(thd, olddbname);
ret= sp_change_db(thd, olddb, 0);
}
DBUG_RETURN(ret);
}
......@@ -496,7 +554,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
ret= execute(thd);
// 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);
Item *it;
......@@ -711,6 +774,32 @@ sp_head::set_info(char *definer, uint definerlen,
m_chistics->comment.length);
}
void
sp_head::reset_thd_mem_root(THD *thd)
{
m_thd_root= thd->mem_root;
thd->mem_root= m_mem_root;
m_free_list= thd->free_list; // Keep the old list
thd->free_list= NULL; // Start a new one
/* Copy the db, since substatements will point to it */
m_thd_db= thd->db;
thd->db= strmake_root(&thd->mem_root, thd->db, thd->db_length);
m_thd= thd;
}
void
sp_head::restore_thd_mem_root(THD *thd)
{
Item *flist= m_free_list; // The old list
m_free_list= thd->free_list; // Get the new one
thd->free_list= flist; // Restore the old one
thd->db= m_thd_db; // Restore the original db pointer
m_mem_root= thd->mem_root;
thd->mem_root= m_thd_root;
m_thd= NULL;
}
int
sp_head::show_create_procedure(THD *thd)
{
......@@ -796,7 +885,10 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
thd->lex->unit.thd= thd; // QQ Not reentrant
freelist= thd->free_list;
thd->free_list= NULL;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id= query_id++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
// Copy WHERE clause pointers to avoid damaging by optimisation
// Also clear ref_pointer_arrays.
......@@ -1089,10 +1181,13 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
DBUG_RETURN(res);
}
/* ------------------------------------------------------------------ */
//
// Security context swapping
//
#ifndef NO_EMBEDDED_ACCESS_CHECKS
void
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
......@@ -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->db_access= thd->db_access;
ctxp->db= thd->db;
ctxp->db_length= thd->db_length;
ctxp->priv_user= thd->priv_user;
strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host));
ctxp->user= thd->user;
......@@ -1122,8 +1215,6 @@ sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
ctxp->changed= FALSE;
thd->master_access= ctxp->master_access;
thd->db_access= ctxp->db_access;
thd->db= ctxp->db;
thd->db_length= ctxp->db_length;
thd->priv_user= ctxp->priv_user;
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
}
......@@ -1143,8 +1234,6 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
ctxp->changed= FALSE;
thd->master_access= ctxp->master_access;
thd->db_access= ctxp->db_access;
thd->db= ctxp->db;
thd->db_length= ctxp->db_length;
thd->priv_user= ctxp->priv_user;
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
}
......
......@@ -37,6 +37,39 @@ class sp_instr;
struct sp_cond_type;
struct sp_pvar;
class sp_name : public Sql_alloc
{
public:
LEX_STRING m_db;
LEX_STRING m_name;
LEX_STRING m_qname;
sp_name(LEX_STRING name)
: m_name(name)
{
m_db.str= m_qname.str= 0;
m_db.length= m_qname.length= 0;
}
sp_name(LEX_STRING db, LEX_STRING name)
: m_db(db), m_name(name)
{
m_qname.str= 0;
m_qname.length= 0;
}
// Init. the qualified name from the db and name.
void init_qname(THD *thd); // thd for memroot allocation
~sp_name()
{}
};
sp_name *
sp_name_current_db_new(THD *thd, LEX_STRING name);
class sp_head : public Sql_alloc
{
sp_head(const sp_head &); /* Prevent use of these */
......@@ -56,6 +89,8 @@ class sp_head : public Sql_alloc
List<char *> m_calls; // Called procedures.
List<char *> m_tables; // Used tables.
#endif
LEX_STRING m_qname; // db.name
LEX_STRING m_db;
LEX_STRING m_name;
LEX_STRING m_params;
LEX_STRING m_retstr; // For FUNCTIONs only
......@@ -83,7 +118,7 @@ class sp_head : public Sql_alloc
// Initialize strings after parsing header
void
init_strings(THD *thd, LEX *lex, LEX_STRING *name);
init_strings(THD *thd, LEX *lex, sp_name *name);
int
create(THD *thd);
......@@ -163,24 +198,10 @@ class sp_head : public Sql_alloc
longlong created, longlong modified,
st_sp_chistics *chistics);
inline void reset_thd_mem_root(THD *thd)
{
m_thd_root= thd->mem_root;
thd->mem_root= m_mem_root;
m_free_list= thd->free_list; // Keep the old list
thd->free_list= NULL; // Start a new one
m_thd= thd;
}
void reset_thd_mem_root(THD *thd);
void restore_thd_mem_root(THD *thd);
inline void restore_thd_mem_root(THD *thd)
{
Item *flist= m_free_list; // The old list
m_free_list= thd->free_list; // Get the new one
thd->free_list= flist; // Restore the old one
m_mem_root= thd->mem_root;
thd->mem_root= m_thd_root;
m_thd= NULL;
}
private:
......@@ -188,6 +209,7 @@ class sp_head : public Sql_alloc
MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
Item *m_free_list; // Where the items go
THD *m_thd; // Set if we have reset mem_root
char *m_thd_db; // Original thd->db pointer
sp_pcontext *m_pcont; // Parse context
List<LEX> m_lex; // Temp. store for the other lex
......@@ -640,8 +662,6 @@ struct st_sp_security_context
bool changed;
uint master_access;
uint db_access;
char *db;
uint db_length;
char *priv_user;
char priv_host[MAX_HOSTNAME];
char *user;
......
......@@ -794,6 +794,7 @@ int acl_getroot_no_password(THD *thd)
{
ulong user_access= NO_ACCESS;
int res= 1;
uint i;
ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot_no_password");
......@@ -810,13 +811,16 @@ int acl_getroot_no_password(THD *thd)
VOID(pthread_mutex_lock(&acl_cache->lock));
thd->master_access= 0;
thd->db_access= 0;
/*
Find acl entry in user database.
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
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*);
if ((!acl_user->user && (!thd->user || !thd->user[0])) ||
......@@ -832,6 +836,22 @@ int acl_getroot_no_password(THD *thd)
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->priv_user= acl_user->user ? thd->user : (char *) "";
......
......@@ -19,6 +19,7 @@
#include "mysql_priv.h"
#include "sql_acl.h"
#include "sp.h"
#include <my_dir.h>
#include <m_ctype.h>
#ifdef __WIN__
......@@ -386,6 +387,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
start_waiting_global_read_lock(thd);
/*
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,
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);
deleted=0L;
init_ftfuncs(thd, &thd->lex->select_lex, 1);
......
......@@ -168,38 +168,6 @@ static int find_keyword(LEX *lex, uint len, bool function)
lex->yylval->symbol.length=len;
return symbol->tok;
}
LEX_STRING ls;
ls.str = (char *)tok; ls.length= len;
if (function && sp_function_exists(current_thd, &ls)) // QQ temp fix
{
lex->safe_to_cache_query= 0;
lex->yylval->lex_str.str= lex->thd->strmake((char*)lex->tok_start, len);
lex->yylval->lex_str.length= len;
return SP_FUNC;
}
#ifdef HAVE_DLOPEN
udf_func *udf;
if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
{
lex->safe_to_cache_query=0;
lex->yylval->udf=udf;
switch (udf->returns) {
case STRING_RESULT:
return (udf->type == UDFTYPE_FUNCTION) ? UDF_CHAR_FUNC : UDA_CHAR_SUM;
case REAL_RESULT:
return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM;
case INT_RESULT:
return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM;
case ROW_RESULT:
default:
// This case should never be choosen
DBUG_ASSERT(0);
return 0;
}
}
#endif
return 0;
}
......
......@@ -22,6 +22,7 @@ class Table_ident;
class sql_exchange;
class LEX_COLUMN;
class sp_head;
class sp_name;
class sp_instr;
class sp_pcontext;
......@@ -604,6 +605,7 @@ typedef struct st_lex
bool derived_tables;
bool safe_to_cache_query;
sp_head *sphead;
sp_name *spname;
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
sp_pcontext *spcont;
HASH spfuns; /* Called functions */
......
......@@ -1086,6 +1086,10 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->query_length=length;
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
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++;
if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
{
......@@ -3101,9 +3105,9 @@ mysql_execute_command(THD *thd)
if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
break;
#ifdef HAVE_DLOPEN
if ((sph= sp_find_function(thd, &lex->udf.name)))
if ((sph= sp_find_function(thd, lex->spname)))
{
net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
net_printf(thd, ER_UDF_EXISTS, lex->spname->m_name.str);
goto error;
}
if (!(res = mysql_create_function(thd,&lex->udf)))
......@@ -3441,9 +3445,10 @@ mysql_execute_command(THD *thd)
{
sp_head *sp;
if (!(sp= sp_find_procedure(thd, &lex->udf.name)))
if (!(sp= sp_find_procedure(thd, lex->spname)))
{
net_printf(thd, ER_SP_DOES_NOT_EXIST, "PROCEDURE", lex->udf.name);
net_printf(thd, ER_SP_DOES_NOT_EXIST, "PROCEDURE",
lex->spname->m_name.str);
goto error;
}
else
......@@ -3521,10 +3526,10 @@ mysql_execute_command(THD *thd)
goto error;
}
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
res= sp_update_procedure(thd, lex->udf.name.str, lex->udf.name.length,
res= sp_update_procedure(thd, lex->spname,
lex->name, newname_len, &lex->sp_chistics);
else
res= sp_update_function(thd, lex->udf.name.str, lex->udf.name.length,
res= sp_update_function(thd, lex->spname,
lex->name, newname_len, &lex->sp_chistics);
switch (res)
{
......@@ -3532,10 +3537,12 @@ mysql_execute_command(THD *thd)
send_ok(thd);
break;
case SP_KEY_NOT_FOUND:
net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),lex->udf.name);
net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),
lex->spname->m_name.str);
goto error;
default:
net_printf(thd, ER_SP_CANT_ALTER, SP_COM_STRING(lex),lex->udf.name);
net_printf(thd, ER_SP_CANT_ALTER, SP_COM_STRING(lex),
lex->spname->m_name.str);
goto error;
}
break;
......@@ -3544,19 +3551,20 @@ mysql_execute_command(THD *thd)
case SQLCOM_DROP_FUNCTION:
{
if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
res= sp_drop_procedure(thd, lex->udf.name.str, lex->udf.name.length);
res= sp_drop_procedure(thd, lex->spname);
else
{
res= sp_drop_function(thd, lex->udf.name.str, lex->udf.name.length);
res= sp_drop_function(thd, lex->spname);
#ifdef HAVE_DLOPEN
if (res == SP_KEY_NOT_FOUND)
{
udf_func *udf = find_udf(lex->udf.name.str, lex->udf.name.length);
udf_func *udf = find_udf(lex->spname->m_name.str,
lex->spname->m_name.length);
if (udf)
{
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0))
goto error;
if (!(res = mysql_drop_function(thd,&lex->udf.name)))
if (!(res = mysql_drop_function(thd,&lex->spname->m_name)))
{
send_ok(thd);
break;
......@@ -3575,17 +3583,17 @@ mysql_execute_command(THD *thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
SP_COM_STRING(lex), lex->udf.name.str);
SP_COM_STRING(lex), lex->spname->m_name.str);
res= 0;
send_ok(thd);
break;
}
net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),
lex->udf.name.str);
lex->spname->m_name.str);
goto error;
default:
net_printf(thd, ER_SP_DROP_FAILED, SP_COM_STRING(lex),
lex->udf.name.str);
lex->spname->m_name.str);
goto error;
}
break;
......@@ -3593,16 +3601,16 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_CREATE_PROC:
{
res= -1;
if (lex->udf.name.length > NAME_LEN)
if (lex->spname->m_name.length > NAME_LEN)
{
net_printf(thd, ER_TOO_LONG_IDENT, lex->udf.name.str);
net_printf(thd, ER_TOO_LONG_IDENT, lex->spname->m_name.str);
goto error;
}
res= sp_show_create_procedure(thd, &lex->udf.name);
res= sp_show_create_procedure(thd, lex->spname);
if (res != SP_OK)
{ /* We don't distinguish between errors for now */
net_printf(thd, ER_SP_DOES_NOT_EXIST,
SP_COM_STRING(lex), lex->udf.name.str);
SP_COM_STRING(lex), lex->spname->m_name.str);
res= 0;
goto error;
}
......@@ -3610,16 +3618,16 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_SHOW_CREATE_FUNC:
{
if (lex->udf.name.length > NAME_LEN)
if (lex->spname->m_name.length > NAME_LEN)
{
net_printf(thd, ER_TOO_LONG_IDENT, lex->udf.name.str);
net_printf(thd, ER_TOO_LONG_IDENT, lex->spname->m_name.str);
goto error;
}
res= sp_show_create_function(thd, &lex->udf.name);
res= sp_show_create_function(thd, lex->spname);
if (res != SP_OK)
{ /* We don't distinguish between errors for now */
net_printf(thd, ER_SP_DOES_NOT_EXIST,
SP_COM_STRING(lex), lex->udf.name.str);
SP_COM_STRING(lex), lex->spname->m_name.str);
res= 0;
goto error;
}
......
......@@ -246,7 +246,11 @@ int mysql_update(THD *thd,
DISK_BUFFER_SIZE, MYF(MY_WME)))
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);
thd->proc_info="Searching rows for update";
uint tmp_limit= limit;
......
This diff is collapsed.
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