mirror of
https://github.com/MariaDB/server.git
synced 2025-09-06 19:08:06 +03:00
Merge rurik.mysql.com:/home/igor/mysql-5.0
into rurik.mysql.com:/home/igor/dev/mysql-5.0-0
This commit is contained in:
@@ -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 @@
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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", "",
|
|||||||
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
|
|||||||
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);
|
|||||||
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;
|
|||||||
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;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
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 );
|
|||||||
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
|
|||||||
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|
|
|||||||
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()
|
|||||||
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|
|
|||||||
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
|
|||||||
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()|
|
|||||||
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
|
|||||||
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;
|
|||||||
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;
|
|||||||
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|
|
|||||||
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)
|
|||||||
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;
|
|||||||
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
|
|||||||
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
|
|||||||
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,,);
|
|||||||
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;
|
|||||||
|
|
||||||
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;
|
|||||||
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;
|
|||||||
# 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;
|
|||||||
|
|
||||||
# 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;
|
|||||||
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|
|
|||||||
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
|
|||||||
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()|
|
|||||||
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|
|
|||||||
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
|
|||||||
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|
|
|||||||
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|
|
|||||||
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
|
|||||||
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)
|
|||||||
|
|
||||||
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 (
|
|||||||
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()
|
|||||||
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)
|
|||||||
#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
|
|||||||
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
|
|||||||
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()
|
|||||||
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
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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 @@ public:
|
|||||||
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 @@ public:
|
|||||||
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 @@ public:
|
|||||||
|
|
||||||
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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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
|
|||||||
"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"
|
||||||
|
401
sql/sp.cc
401
sql/sp.cc
@@ -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 @@
|
|||||||
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
|
|||||||
|
|
||||||
/* *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,
|
|||||||
|
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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 @@ done:
|
|||||||
|
|
||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
|
|
||||||
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,
|
|||||||
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
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
|||||||
|
|
||||||
|
|
||||||
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)
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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)
|
|||||||
|
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
*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);
|
||||||
|
}
|
||||||
|
40
sql/sp.h
40
sql/sp.h
@@ -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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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);
|
|||||||
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();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
157
sql/sp_head.cc
157
sql/sp_head.cc
@@ -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)
|
|||||||
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
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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;
|
|||||||
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 @@ public:
|
|||||||
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 @@ public:
|
|||||||
|
|
||||||
// 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 @@ public:
|
|||||||
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 @@ private:
|
|||||||
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
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
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;
|
|||||||
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
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
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;
|
||||||
|
|
||||||
|
210
sql/sql_yacc.yy
210
sql/sql_yacc.yy
@@ -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);
|
|||||||
%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);
|
|||||||
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);
|
|||||||
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);
|
|||||||
%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
|
|||||||
%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:
|
|||||||
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:
|
|||||||
{
|
{
|
||||||
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:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
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:
|
|||||||
{
|
{
|
||||||
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:
|
|||||||
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:
|
|||||||
;
|
;
|
||||||
|
|
||||||
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:
|
|||||||
/* 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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
{ $$= 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;
|
||||||
|
sp_name *name= new sp_name($1, $3);
|
||||||
|
|
||||||
|
name->init_qname(YYTHD);
|
||||||
|
sp_add_fun_to_lex(Lex, name);
|
||||||
|
if ($5)
|
||||||
|
$$= new Item_func_sp(name, *$5);
|
||||||
|
else
|
||||||
|
$$= new Item_func_sp(name);
|
||||||
|
}
|
||||||
|
| 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)
|
||||||
|
$$ = new Item_func_udf_str(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_func_udf_str(udf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_sum_udf_str(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_sum_udf_str(udf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REAL_RESULT:
|
||||||
|
if (udf->type == UDFTYPE_FUNCTION)
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_func_udf_float(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_func_udf_float(udf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_sum_udf_float(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_sum_udf_float(udf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT_RESULT:
|
||||||
|
if (udf->type == UDFTYPE_FUNCTION)
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_func_udf_int(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_func_udf_int(udf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($3 != NULL)
|
||||||
|
$$ = new Item_sum_udf_int(udf, *$3);
|
||||||
|
else
|
||||||
|
$$ = new Item_sum_udf_int(udf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* HAVE_DLOPEN */
|
||||||
|
{
|
||||||
|
sp_name *name= sp_name_current_db_new(YYTHD, $1);
|
||||||
|
|
||||||
|
sp_add_fun_to_lex(Lex, name);
|
||||||
if ($3)
|
if ($3)
|
||||||
$$= new Item_func_sp($1, *$3);
|
$$= new Item_func_sp(name, *$3);
|
||||||
else
|
else
|
||||||
$$= new Item_func_sp($1);
|
$$= new Item_func_sp(name);
|
||||||
}
|
}
|
||||||
| UDA_CHAR_SUM '(' udf_expr_list ')'
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_sum_udf_str($1, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_sum_udf_str($1);
|
|
||||||
}
|
|
||||||
| UDA_FLOAT_SUM '(' udf_expr_list ')'
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_sum_udf_float($1, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_sum_udf_float($1);
|
|
||||||
}
|
|
||||||
| UDA_INT_SUM '(' udf_expr_list ')'
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_sum_udf_int($1, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_sum_udf_int($1);
|
|
||||||
}
|
|
||||||
| UDF_CHAR_FUNC '(' udf_expr_list ')'
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_func_udf_str($1, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_func_udf_str($1);
|
|
||||||
}
|
|
||||||
| UDF_FLOAT_FUNC '(' udf_expr_list ')'
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_func_udf_float($1, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_func_udf_float($1);
|
|
||||||
}
|
|
||||||
| UDF_INT_FUNC '(' udf_expr_list ')'
|
|
||||||
{
|
|
||||||
if ($3 != NULL)
|
|
||||||
$$ = new Item_func_udf_int($1, *$3);
|
|
||||||
else
|
|
||||||
$$ = new Item_func_udf_int($1);
|
|
||||||
}
|
}
|
||||||
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
|
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
|
||||||
{
|
{
|
||||||
@@ -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:
|
|||||||
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:
|
|||||||
{
|
{
|
||||||
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
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user