mirror of
https://github.com/MariaDB/server.git
synced 2025-01-30 10:31:54 +01:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/alik/Documents/AllProgs/MySQL/devel/5.0-sp-vars-merge-2
This commit is contained in:
commit
5b981a4844
41 changed files with 4485 additions and 1252 deletions
122
mysql-test/include/sp-vars.inc
Normal file
122
mysql-test/include/sp-vars.inc
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
delimiter |;
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE PROCEDURE sp_vars_check_dflt()
|
||||||
|
BEGIN
|
||||||
|
DECLARE v1 TINYINT DEFAULT 1e200;
|
||||||
|
DECLARE v1u TINYINT UNSIGNED DEFAULT 1e200;
|
||||||
|
DECLARE v2 TINYINT DEFAULT -1e200;
|
||||||
|
DECLARE v2u TINYINT UNSIGNED DEFAULT -1e200;
|
||||||
|
DECLARE v3 TINYINT DEFAULT 300;
|
||||||
|
DECLARE v3u TINYINT UNSIGNED DEFAULT 300;
|
||||||
|
DECLARE v4 TINYINT DEFAULT -300;
|
||||||
|
DECLARE v4u TINYINT UNSIGNED DEFAULT -300;
|
||||||
|
|
||||||
|
DECLARE v5 TINYINT DEFAULT 10 * 10 * 10;
|
||||||
|
DECLARE v5u TINYINT UNSIGNED DEFAULT 10 * 10 * 10;
|
||||||
|
DECLARE v6 TINYINT DEFAULT -10 * 10 * 10;
|
||||||
|
DECLARE v6u TINYINT UNSIGNED DEFAULT -10 * 10 * 10;
|
||||||
|
|
||||||
|
DECLARE v7 TINYINT DEFAULT '10';
|
||||||
|
DECLARE v8 TINYINT DEFAULT '10 ';
|
||||||
|
DECLARE v9 TINYINT DEFAULT ' 10 ';
|
||||||
|
DECLARE v10 TINYINT DEFAULT 'String 10 ';
|
||||||
|
DECLARE v11 TINYINT DEFAULT 'String10';
|
||||||
|
DECLARE v12 TINYINT DEFAULT '10 String';
|
||||||
|
DECLARE v13 TINYINT DEFAULT '10String';
|
||||||
|
DECLARE v14 TINYINT DEFAULT concat('10', ' ');
|
||||||
|
DECLARE v15 TINYINT DEFAULT concat(' ', '10');
|
||||||
|
DECLARE v16 TINYINT DEFAULT concat('Hello, ', 'world');
|
||||||
|
|
||||||
|
DECLARE v17 DECIMAL(64, 2) DEFAULT 12;
|
||||||
|
DECLARE v18 DECIMAL(64, 2) DEFAULT 12.123;
|
||||||
|
DECLARE v19 DECIMAL(64, 2) DEFAULT 11 + 1;
|
||||||
|
DECLARE v20 DECIMAL(64, 2) DEFAULT 12 + 0.123;
|
||||||
|
|
||||||
|
SELECT v1, v1u, v2, v2u, v3, v3u, v4, v4u;
|
||||||
|
SELECT v5, v5u, v6, v6u;
|
||||||
|
SELECT v7, v8, v9, v10, v11, v12, v13, v14, v15, v16;
|
||||||
|
SELECT v17, v18, v19, v20;
|
||||||
|
END|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE PROCEDURE sp_vars_check_assignment()
|
||||||
|
BEGIN
|
||||||
|
DECLARE i1, i2, i3, i4 TINYINT;
|
||||||
|
DECLARE u1, u2, u3, u4 TINYINT UNSIGNED;
|
||||||
|
DECLARE d1, d2, d3 DECIMAL(64, 2);
|
||||||
|
|
||||||
|
SET i1 = 1e200;
|
||||||
|
SET i2 = -1e200;
|
||||||
|
SET i3 = 300;
|
||||||
|
SET i4 = -300;
|
||||||
|
|
||||||
|
SELECT i1, i2, i3, i4;
|
||||||
|
|
||||||
|
SET i1 = 10 * 10 * 10;
|
||||||
|
SET i2 = -10 * 10 * 10;
|
||||||
|
SET i3 = sign(10 * 10) * 10 * 20;
|
||||||
|
SET i4 = sign(-10 * 10) * -10 * 20;
|
||||||
|
|
||||||
|
SELECT i1, i2, i3, i4;
|
||||||
|
|
||||||
|
SET u1 = 1e200;
|
||||||
|
SET u2 = -1e200;
|
||||||
|
SET u3 = 300;
|
||||||
|
SET u4 = -300;
|
||||||
|
|
||||||
|
SELECT u1, u2, u3, u4;
|
||||||
|
|
||||||
|
SET u1 = 10 * 10 * 10;
|
||||||
|
SET u2 = -10 * 10 * 10;
|
||||||
|
SET u3 = sign(10 * 10) * 10 * 20;
|
||||||
|
SET u4 = sign(-10 * 10) * -10 * 20;
|
||||||
|
|
||||||
|
SELECT u1, u2, u3, u4;
|
||||||
|
|
||||||
|
SET d1 = 1234;
|
||||||
|
SET d2 = 1234.12;
|
||||||
|
SET d3 = 1234.1234;
|
||||||
|
|
||||||
|
SELECT d1, d2, d3;
|
||||||
|
|
||||||
|
SET d1 = 12 * 100 + 34;
|
||||||
|
SET d2 = 12 * 100 + 34 + 0.12;
|
||||||
|
SET d3 = 12 * 100 + 34 + 0.1234;
|
||||||
|
|
||||||
|
SELECT d1, d2, d3;
|
||||||
|
END|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE FUNCTION sp_vars_check_ret1() RETURNS TINYINT
|
||||||
|
BEGIN
|
||||||
|
RETURN 1e200;
|
||||||
|
END|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE FUNCTION sp_vars_check_ret2() RETURNS TINYINT
|
||||||
|
BEGIN
|
||||||
|
RETURN 10 * 10 * 10;
|
||||||
|
END|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE FUNCTION sp_vars_check_ret3() RETURNS TINYINT
|
||||||
|
BEGIN
|
||||||
|
RETURN 'Hello, world';
|
||||||
|
END|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE FUNCTION sp_vars_check_ret4() RETURNS DECIMAL(64, 2)
|
||||||
|
BEGIN
|
||||||
|
RETURN 12 * 10 + 34 + 0.1234;
|
||||||
|
END|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
delimiter ;|
|
|
@ -2317,7 +2317,7 @@ CREATE TABLE t2(c2 char(2)) default charset = ujis;
|
||||||
INSERT INTO t1 VALUES(_ujis 0xA4A2);
|
INSERT INTO t1 VALUES(_ujis 0xA4A2);
|
||||||
CREATE PROCEDURE sp1()
|
CREATE PROCEDURE sp1()
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE a CHAR(1);
|
DECLARE a CHAR(2) CHARSET ujis;
|
||||||
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
||||||
OPEN cur1;
|
OPEN cur1;
|
||||||
FETCH cur1 INTO a;
|
FETCH cur1 INTO a;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
drop database if exists mysqltest1;
|
||||||
create schema foo;
|
create schema foo;
|
||||||
show create schema foo;
|
show create schema foo;
|
||||||
Database Create Database
|
Database Create Database
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
drop table if exists t1,t2;
|
drop table if exists t1,t2;
|
||||||
drop table if exists t1aa,t2aa;
|
drop table if exists t1aa,t2aa;
|
||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
|
drop database if exists mysqltest1;
|
||||||
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
||||||
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
||||||
flush privileges;
|
flush privileges;
|
||||||
|
|
|
@ -10,5 +10,5 @@ user()
|
||||||
#
|
#
|
||||||
show processlist;
|
show processlist;
|
||||||
Id User Host db Command Time State Info
|
Id User Host db Command Time State Info
|
||||||
# root # test Sleep # NULL
|
<id> root <host> test <command> <time> <state> <info>
|
||||||
# root # test Query # NULL show processlist
|
<id> root <host> test <command> <time> <state> <info>
|
||||||
|
|
|
@ -25,6 +25,7 @@ count(*)
|
||||||
select count(*) from t2;
|
select count(*) from t2;
|
||||||
count(*)
|
count(*)
|
||||||
0
|
0
|
||||||
|
drop procedure if exists p1;
|
||||||
create procedure p1()
|
create procedure p1()
|
||||||
begin
|
begin
|
||||||
declare done integer default 0;
|
declare done integer default 0;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
drop procedure if exists p1|
|
||||||
|
drop procedure if exists p2|
|
||||||
create procedure p1()
|
create procedure p1()
|
||||||
begin
|
begin
|
||||||
prepare stmt from "select 1";
|
prepare stmt from "select 1";
|
||||||
|
|
1077
mysql-test/r/sp-vars.result
Normal file
1077
mysql-test/r/sp-vars.result
Normal file
File diff suppressed because it is too large
Load diff
|
@ -248,13 +248,13 @@ return i+1|
|
||||||
call sub1("sub1a", (select 7))|
|
call sub1("sub1a", (select 7))|
|
||||||
call sub1("sub1b", (select max(i) from t2))|
|
call sub1("sub1b", (select max(i) from t2))|
|
||||||
call sub1("sub1c", (select i,d from t2 limit 1))|
|
call sub1("sub1c", (select i,d from t2 limit 1))|
|
||||||
|
ERROR 21000: Operand should contain 1 column(s)
|
||||||
call sub1("sub1d", (select 1 from (select 1) a))|
|
call sub1("sub1d", (select 1 from (select 1) a))|
|
||||||
call sub2("sub2")|
|
call sub2("sub2")|
|
||||||
select * from t1|
|
select * from t1|
|
||||||
id data
|
id data
|
||||||
sub1a 7
|
sub1a 7
|
||||||
sub1b 3
|
sub1b 3
|
||||||
sub1c 1
|
|
||||||
sub1d 1
|
sub1d 1
|
||||||
sub2 6
|
sub2 6
|
||||||
select sub3((select max(i) from t2))|
|
select sub3((select max(i) from t2))|
|
||||||
|
@ -2686,7 +2686,7 @@ call bug8937()|
|
||||||
s x y z
|
s x y z
|
||||||
16 3 1 6
|
16 3 1 6
|
||||||
a
|
a
|
||||||
3.2000
|
3.2
|
||||||
drop procedure bug8937|
|
drop procedure bug8937|
|
||||||
delete from t1|
|
delete from t1|
|
||||||
drop procedure if exists bug6900|
|
drop procedure if exists bug6900|
|
||||||
|
@ -2890,21 +2890,30 @@ create function bug9775(v1 char(1)) returns enum('a','b') return v1|
|
||||||
select bug9775('a'),bug9775('b'),bug9775('c')|
|
select bug9775('a'),bug9775('b'),bug9775('c')|
|
||||||
bug9775('a') bug9775('b') bug9775('c')
|
bug9775('a') bug9775('b') bug9775('c')
|
||||||
a b
|
a b
|
||||||
|
Warnings:
|
||||||
|
Warning 1265 Data truncated for column 'bug9775('c')' at row 1
|
||||||
drop function bug9775|
|
drop function bug9775|
|
||||||
create function bug9775(v1 int) returns enum('a','b') return v1|
|
create function bug9775(v1 int) returns enum('a','b') return v1|
|
||||||
select bug9775(1),bug9775(2),bug9775(3)|
|
select bug9775(1),bug9775(2),bug9775(3)|
|
||||||
bug9775(1) bug9775(2) bug9775(3)
|
bug9775(1) bug9775(2) bug9775(3)
|
||||||
a b
|
a b
|
||||||
|
Warnings:
|
||||||
|
Warning 1265 Data truncated for column 'bug9775(3)' at row 1
|
||||||
drop function bug9775|
|
drop function bug9775|
|
||||||
create function bug9775(v1 char(1)) returns set('a','b') return v1|
|
create function bug9775(v1 char(1)) returns set('a','b') return v1|
|
||||||
select bug9775('a'),bug9775('b'),bug9775('a,b'),bug9775('c')|
|
select bug9775('a'),bug9775('b'),bug9775('a,b'),bug9775('c')|
|
||||||
bug9775('a') bug9775('b') bug9775('a,b') bug9775('c')
|
bug9775('a') bug9775('b') bug9775('a,b') bug9775('c')
|
||||||
a b a,b
|
a b a
|
||||||
|
Warnings:
|
||||||
|
Warning 1265 Data truncated for column 'v1' at row 1
|
||||||
|
Warning 1265 Data truncated for column 'bug9775('c')' at row 1
|
||||||
drop function bug9775|
|
drop function bug9775|
|
||||||
create function bug9775(v1 int) returns set('a','b') return v1|
|
create function bug9775(v1 int) returns set('a','b') return v1|
|
||||||
select bug9775(1),bug9775(2),bug9775(3),bug9775(4)|
|
select bug9775(1),bug9775(2),bug9775(3),bug9775(4)|
|
||||||
bug9775(1) bug9775(2) bug9775(3) bug9775(4)
|
bug9775(1) bug9775(2) bug9775(3) bug9775(4)
|
||||||
a b a,b
|
a b a,b
|
||||||
|
Warnings:
|
||||||
|
Warning 1265 Data truncated for column 'bug9775(4)' at row 1
|
||||||
drop function bug9775|
|
drop function bug9775|
|
||||||
drop function if exists bug8861|
|
drop function if exists bug8861|
|
||||||
create function bug8861(v1 int) returns year return v1|
|
create function bug8861(v1 int) returns year return v1|
|
||||||
|
@ -2927,12 +2936,10 @@ create procedure bug9004_2(x char(16))
|
||||||
call bug9004_1(x)|
|
call bug9004_1(x)|
|
||||||
call bug9004_1('12345678901234567')|
|
call bug9004_1('12345678901234567')|
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1265 Data truncated for column 'id' at row 1
|
Warning 1265 Data truncated for column 'x' at row 1
|
||||||
Warning 1265 Data truncated for column 'id' at row 2
|
|
||||||
call bug9004_2('12345678901234567890')|
|
call bug9004_2('12345678901234567890')|
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1265 Data truncated for column 'id' at row 1
|
Warning 1265 Data truncated for column 'x' at row 1
|
||||||
Warning 1265 Data truncated for column 'id' at row 2
|
|
||||||
delete from t1|
|
delete from t1|
|
||||||
drop procedure bug9004_1|
|
drop procedure bug9004_1|
|
||||||
drop procedure bug9004_2|
|
drop procedure bug9004_2|
|
||||||
|
@ -3527,14 +3534,15 @@ end|
|
||||||
call bug12589_1()|
|
call bug12589_1()|
|
||||||
Table Create Table
|
Table Create Table
|
||||||
tm1 CREATE TEMPORARY TABLE `tm1` (
|
tm1 CREATE TEMPORARY TABLE `tm1` (
|
||||||
`spv1` decimal(1,0) unsigned default NULL
|
`spv1` decimal(3,3) default NULL
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1292 Truncated incorrect DECIMAL value: 'test'
|
Warning 1264 Out of range value adjusted for column 'spv1' at row 1
|
||||||
|
Warning 1366 Incorrect decimal value: 'test' for column 'spv1' at row 1
|
||||||
call bug12589_2()|
|
call bug12589_2()|
|
||||||
Table Create Table
|
Table Create Table
|
||||||
tm1 CREATE TEMPORARY TABLE `tm1` (
|
tm1 CREATE TEMPORARY TABLE `tm1` (
|
||||||
`spv1` decimal(6,3) unsigned default NULL
|
`spv1` decimal(6,3) default NULL
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
call bug12589_3()|
|
call bug12589_3()|
|
||||||
Table Create Table
|
Table Create Table
|
||||||
|
@ -4016,34 +4024,37 @@ create procedure bug14643_1()
|
||||||
begin
|
begin
|
||||||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||||
begin
|
begin
|
||||||
declare v int default x;
|
declare v int default undefined_var;
|
||||||
if v = 1 then
|
if v = 1 then
|
||||||
select 1;
|
select 1;
|
||||||
else
|
else
|
||||||
select 2;
|
select v, isnull(v);
|
||||||
end if;
|
end if;
|
||||||
end;
|
end;
|
||||||
end|
|
end|
|
||||||
create procedure bug14643_2()
|
create procedure bug14643_2()
|
||||||
begin
|
begin
|
||||||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||||
case x
|
case undefined_var
|
||||||
when 1 then
|
when 1 then
|
||||||
select 1;
|
select 1;
|
||||||
else
|
else
|
||||||
select 2;
|
select 2;
|
||||||
end case;
|
end case;
|
||||||
|
select undefined_var;
|
||||||
end|
|
end|
|
||||||
call bug14643_1()|
|
call bug14643_1()|
|
||||||
Handler
|
Handler
|
||||||
boo
|
boo
|
||||||
2
|
v isnull(v)
|
||||||
2
|
NULL 1
|
||||||
call bug14643_2()|
|
call bug14643_2()|
|
||||||
Handler
|
Handler
|
||||||
boo
|
boo
|
||||||
2
|
2
|
||||||
2
|
2
|
||||||
|
Handler
|
||||||
|
boo
|
||||||
drop procedure bug14643_1|
|
drop procedure bug14643_1|
|
||||||
drop procedure bug14643_2|
|
drop procedure bug14643_2|
|
||||||
drop procedure if exists bug14304|
|
drop procedure if exists bug14304|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using_big_test
|
DROP TABLE IF EXISTS t1, t2;
|
||||||
0
|
|
||||||
CREATE TABLE t1 (id INTEGER);
|
CREATE TABLE t1 (id INTEGER);
|
||||||
CREATE TABLE t2 (id INTEGER);
|
CREATE TABLE t2 (id INTEGER);
|
||||||
INSERT INTO t1 (id) VALUES (1), (1), (1),(1);
|
INSERT INTO t1 (id) VALUES (1), (1), (1),(1);
|
||||||
|
@ -40,19 +39,19 @@ AVG(DISTINCT id)
|
||||||
512.5000
|
512.5000
|
||||||
SELECT SUM(DISTINCT id)/COUNT(DISTINCT id) FROM t1 GROUP BY id % 13;
|
SELECT SUM(DISTINCT id)/COUNT(DISTINCT id) FROM t1 GROUP BY id % 13;
|
||||||
SUM(DISTINCT id)/COUNT(DISTINCT id)
|
SUM(DISTINCT id)/COUNT(DISTINCT id)
|
||||||
513.50000
|
513.5000
|
||||||
508.00000
|
508.0000
|
||||||
509.00000
|
509.0000
|
||||||
510.00000
|
510.0000
|
||||||
511.00000
|
511.0000
|
||||||
512.00000
|
512.0000
|
||||||
513.00000
|
513.0000
|
||||||
514.00000
|
514.0000
|
||||||
515.00000
|
515.0000
|
||||||
516.00000
|
516.0000
|
||||||
517.00000
|
517.0000
|
||||||
511.50000
|
511.5000
|
||||||
512.50000
|
512.5000
|
||||||
INSERT INTO t1 SELECT id+1024 FROM t1;
|
INSERT INTO t1 SELECT id+1024 FROM t1;
|
||||||
INSERT INTO t1 SELECT id+2048 FROM t1;
|
INSERT INTO t1 SELECT id+2048 FROM t1;
|
||||||
INSERT INTO t1 SELECT id+4096 FROM t1;
|
INSERT INTO t1 SELECT id+4096 FROM t1;
|
||||||
|
|
|
@ -1,11 +1,26 @@
|
||||||
drop procedure if exists sp1;
|
drop procedure if exists sp1;
|
||||||
create procedure sp1 () begin
|
CREATE PROCEDURE sp1()
|
||||||
declare v1, v2, v3, v4 decimal(16,12); declare v5 int;
|
BEGIN
|
||||||
set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0;
|
DECLARE v1, v2, v3, v4 DECIMAL(28,12);
|
||||||
while v5 < 100000 do
|
DECLARE v3_2, v4_2 DECIMAL(28, 12);
|
||||||
set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1;
|
DECLARE counter INT;
|
||||||
end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;//
|
SET v1 = 1;
|
||||||
|
SET v2 = 2;
|
||||||
|
SET v3 = 1000000000000;
|
||||||
|
SET v4 = 2000000000000;
|
||||||
|
SET counter = 0;
|
||||||
|
WHILE counter < 100000 DO
|
||||||
|
SET v1 = v1 + 0.000000000001;
|
||||||
|
SET v2 = v2 - 0.000000000001;
|
||||||
|
SET v3 = v3 + 1;
|
||||||
|
SET v4 = v4 - 1;
|
||||||
|
SET counter = counter + 1;
|
||||||
|
END WHILE;
|
||||||
|
SET v3_2 = v3 * 0.000000000001;
|
||||||
|
SET v4_2 = v4 * 0.000000000001;
|
||||||
|
SELECT v1, v2, v3, v3_2, v4, v4_2;
|
||||||
|
END//
|
||||||
call sp1()//
|
call sp1()//
|
||||||
v1 v2 v3 * 0.000000000001 v4 * 0.000000000001
|
v1 v2 v3 v3_2 v4 v4_2
|
||||||
1.000000100000 1.999999900000 1.000000100000 1.999999900000
|
1.000000100000 1.999999900000 1000000100000.000000000000 1.000000100000 1999999900000.000000000000 1.999999900000
|
||||||
drop procedure sp1;
|
drop procedure sp1;
|
||||||
|
|
1273
mysql-test/sp-vars.test
Normal file
1273
mysql-test/sp-vars.test
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1170,7 +1170,7 @@ INSERT INTO t1 VALUES(_ujis 0xA4A2);
|
||||||
DELIMITER |;
|
DELIMITER |;
|
||||||
CREATE PROCEDURE sp1()
|
CREATE PROCEDURE sp1()
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE a CHAR(1);
|
DECLARE a CHAR(2) CHARSET ujis;
|
||||||
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
||||||
OPEN cur1;
|
OPEN cur1;
|
||||||
FETCH cur1 INTO a;
|
FETCH cur1 INTO a;
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#
|
#
|
||||||
# Just a couple of tests to make sure that schema works.
|
# Just a couple of tests to make sure that schema works.
|
||||||
#
|
#
|
||||||
|
# Drop mysqltest1 database, as it can left from the previous tests.
|
||||||
|
#
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop database if exists mysqltest1;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
create schema foo;
|
create schema foo;
|
||||||
show create schema foo;
|
show create schema foo;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
drop table if exists t1,t2;
|
drop table if exists t1,t2;
|
||||||
drop table if exists t1aa,t2aa;
|
drop table if exists t1aa,t2aa;
|
||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
|
drop database if exists mysqltest1;
|
||||||
|
|
||||||
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
||||||
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
||||||
|
|
|
@ -15,6 +15,6 @@ DROP USER mysqltest_1@'127.0.0.1/255.255.255.255';
|
||||||
connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, );
|
connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, );
|
||||||
--replace_column 1 #
|
--replace_column 1 #
|
||||||
select user();
|
select user();
|
||||||
--replace_column 1 # 6 # 3 #
|
--replace_column 1 <id> 3 <host> 5 <command> 6 <time> 7 <state> 8 <info>
|
||||||
show processlist;
|
show processlist;
|
||||||
connection default;
|
connection default;
|
||||||
|
|
|
@ -52,6 +52,9 @@ while ($1)
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
select count(*) from t1;
|
select count(*) from t1;
|
||||||
select count(*) from t2;
|
select count(*) from t2;
|
||||||
|
--disable_warnings
|
||||||
|
drop procedure if exists p1;
|
||||||
|
--enable_warnings
|
||||||
delimiter |;
|
delimiter |;
|
||||||
create procedure p1()
|
create procedure p1()
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
delimiter |;
|
delimiter |;
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop procedure if exists p1|
|
||||||
|
drop procedure if exists p2|
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Test Dynamic SQL in stored procedures. #############################
|
# Test Dynamic SQL in stored procedures. #############################
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
|
@ -367,6 +367,7 @@ create function sub3(i int) returns int
|
||||||
|
|
||||||
call sub1("sub1a", (select 7))|
|
call sub1("sub1a", (select 7))|
|
||||||
call sub1("sub1b", (select max(i) from t2))|
|
call sub1("sub1b", (select max(i) from t2))|
|
||||||
|
--error ER_OPERAND_COLUMNS
|
||||||
call sub1("sub1c", (select i,d from t2 limit 1))|
|
call sub1("sub1c", (select i,d from t2 limit 1))|
|
||||||
call sub1("sub1d", (select 1 from (select 1) a))|
|
call sub1("sub1d", (select 1 from (select 1) a))|
|
||||||
call sub2("sub2")|
|
call sub2("sub2")|
|
||||||
|
@ -4797,12 +4798,12 @@ begin
|
||||||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||||
|
|
||||||
begin
|
begin
|
||||||
declare v int default x;
|
declare v int default undefined_var;
|
||||||
|
|
||||||
if v = 1 then
|
if v = 1 then
|
||||||
select 1;
|
select 1;
|
||||||
else
|
else
|
||||||
select 2;
|
select v, isnull(v);
|
||||||
end if;
|
end if;
|
||||||
end;
|
end;
|
||||||
end|
|
end|
|
||||||
|
@ -4811,12 +4812,14 @@ create procedure bug14643_2()
|
||||||
begin
|
begin
|
||||||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||||
|
|
||||||
case x
|
case undefined_var
|
||||||
when 1 then
|
when 1 then
|
||||||
select 1;
|
select 1;
|
||||||
else
|
else
|
||||||
select 2;
|
select 2;
|
||||||
end case;
|
end case;
|
||||||
|
|
||||||
|
select undefined_var;
|
||||||
end|
|
end|
|
||||||
|
|
||||||
call bug14643_1()|
|
call bug14643_1()|
|
||||||
|
|
|
@ -12,12 +12,31 @@ drop procedure if exists sp1;
|
||||||
|
|
||||||
delimiter //;
|
delimiter //;
|
||||||
#
|
#
|
||||||
create procedure sp1 () begin
|
CREATE PROCEDURE sp1()
|
||||||
declare v1, v2, v3, v4 decimal(16,12); declare v5 int;
|
BEGIN
|
||||||
set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0;
|
DECLARE v1, v2, v3, v4 DECIMAL(28,12);
|
||||||
while v5 < 100000 do
|
DECLARE v3_2, v4_2 DECIMAL(28, 12);
|
||||||
set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1;
|
DECLARE counter INT;
|
||||||
end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;//
|
|
||||||
|
SET v1 = 1;
|
||||||
|
SET v2 = 2;
|
||||||
|
SET v3 = 1000000000000;
|
||||||
|
SET v4 = 2000000000000;
|
||||||
|
SET counter = 0;
|
||||||
|
|
||||||
|
WHILE counter < 100000 DO
|
||||||
|
SET v1 = v1 + 0.000000000001;
|
||||||
|
SET v2 = v2 - 0.000000000001;
|
||||||
|
SET v3 = v3 + 1;
|
||||||
|
SET v4 = v4 - 1;
|
||||||
|
SET counter = counter + 1;
|
||||||
|
END WHILE;
|
||||||
|
|
||||||
|
SET v3_2 = v3 * 0.000000000001;
|
||||||
|
SET v4_2 = v4 * 0.000000000001;
|
||||||
|
|
||||||
|
SELECT v1, v2, v3, v3_2, v4, v4_2;
|
||||||
|
END//
|
||||||
#
|
#
|
||||||
call sp1()//
|
call sp1()//
|
||||||
#-- should return
|
#-- should return
|
||||||
|
|
347
sql/field.cc
347
sql/field.cc
|
@ -6759,7 +6759,10 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
|
||||||
{
|
{
|
||||||
flags|= BLOB_FLAG;
|
flags|= BLOB_FLAG;
|
||||||
if (table)
|
if (table)
|
||||||
|
{
|
||||||
table->s->blob_fields++;
|
table->s->blob_fields++;
|
||||||
|
/* TODO: why do not fill table->s->blob_field array here? */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8283,6 +8286,350 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize field definition for create
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
thd Thread handle
|
||||||
|
fld_name Field name
|
||||||
|
fld_type Field type
|
||||||
|
fld_length Field length
|
||||||
|
fld_decimals Decimal (if any)
|
||||||
|
fld_type_modifier Additional type information
|
||||||
|
fld_default_value Field default value (if any)
|
||||||
|
fld_on_update_value The value of ON UPDATE clause
|
||||||
|
fld_comment Field comment
|
||||||
|
fld_change Field change
|
||||||
|
fld_interval_list Interval list (if any)
|
||||||
|
fld_charset Field charset
|
||||||
|
fld_geom_type Field geometry type (if any)
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
FALSE on success
|
||||||
|
TRUE on error
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
|
||||||
|
char *fld_length, char *fld_decimals,
|
||||||
|
uint fld_type_modifier, Item *fld_default_value,
|
||||||
|
Item *fld_on_update_value, LEX_STRING *fld_comment,
|
||||||
|
char *fld_change, List<String> *fld_interval_list,
|
||||||
|
CHARSET_INFO *fld_charset, uint fld_geom_type)
|
||||||
|
{
|
||||||
|
uint sign_len, allowed_type_modifier= 0;
|
||||||
|
ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
|
||||||
|
|
||||||
|
DBUG_ENTER("create_field::init()");
|
||||||
|
|
||||||
|
field= 0;
|
||||||
|
field_name= fld_name;
|
||||||
|
def= fld_default_value;
|
||||||
|
flags= fld_type_modifier;
|
||||||
|
unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
|
||||||
|
Field::NEXT_NUMBER : Field::NONE);
|
||||||
|
decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0;
|
||||||
|
if (decimals >= NOT_FIXED_DEC)
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name,
|
||||||
|
NOT_FIXED_DEC-1);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
sql_type= fld_type;
|
||||||
|
length= 0;
|
||||||
|
change= fld_change;
|
||||||
|
interval= 0;
|
||||||
|
pack_length= key_length= 0;
|
||||||
|
charset= fld_charset;
|
||||||
|
geom_type= (Field::geometry_type) fld_geom_type;
|
||||||
|
interval_list.empty();
|
||||||
|
|
||||||
|
comment= *fld_comment;
|
||||||
|
/*
|
||||||
|
Set flag if this field doesn't have a default value
|
||||||
|
*/
|
||||||
|
if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
|
||||||
|
(fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP)
|
||||||
|
flags|= NO_DEFAULT_VALUE_FLAG;
|
||||||
|
|
||||||
|
if (fld_length && !(length= (uint) atoi(fld_length)))
|
||||||
|
fld_length= 0; /* purecov: inspected */
|
||||||
|
sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
|
||||||
|
|
||||||
|
switch (fld_type) {
|
||||||
|
case FIELD_TYPE_TINY:
|
||||||
|
if (!fld_length)
|
||||||
|
length= MAX_TINYINT_WIDTH+sign_len;
|
||||||
|
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_SHORT:
|
||||||
|
if (!fld_length)
|
||||||
|
length= MAX_SMALLINT_WIDTH+sign_len;
|
||||||
|
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_INT24:
|
||||||
|
if (!fld_length)
|
||||||
|
length= MAX_MEDIUMINT_WIDTH+sign_len;
|
||||||
|
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_LONG:
|
||||||
|
if (!fld_length)
|
||||||
|
length= MAX_INT_WIDTH+sign_len;
|
||||||
|
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_LONGLONG:
|
||||||
|
if (!fld_length)
|
||||||
|
length= MAX_BIGINT_WIDTH;
|
||||||
|
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_NULL:
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_NEWDECIMAL:
|
||||||
|
if (!fld_length && !decimals)
|
||||||
|
length= 10;
|
||||||
|
if (length > DECIMAL_MAX_PRECISION)
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
|
||||||
|
DECIMAL_MAX_PRECISION);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
if (length < decimals)
|
||||||
|
{
|
||||||
|
my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
length=
|
||||||
|
my_decimal_precision_to_length(length, decimals,
|
||||||
|
fld_type_modifier & UNSIGNED_FLAG);
|
||||||
|
pack_length=
|
||||||
|
my_decimal_get_binary_size(length, decimals);
|
||||||
|
break;
|
||||||
|
case MYSQL_TYPE_VARCHAR:
|
||||||
|
/*
|
||||||
|
Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
|
||||||
|
if they don't have a default value
|
||||||
|
*/
|
||||||
|
max_field_charlength= MAX_FIELD_VARCHARLENGTH;
|
||||||
|
break;
|
||||||
|
case MYSQL_TYPE_STRING:
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_BLOB:
|
||||||
|
case FIELD_TYPE_TINY_BLOB:
|
||||||
|
case FIELD_TYPE_LONG_BLOB:
|
||||||
|
case FIELD_TYPE_MEDIUM_BLOB:
|
||||||
|
case FIELD_TYPE_GEOMETRY:
|
||||||
|
if (fld_default_value)
|
||||||
|
{
|
||||||
|
/* Allow empty as default value. */
|
||||||
|
String str,*res;
|
||||||
|
res= fld_default_value->val_str(&str);
|
||||||
|
if (res->length())
|
||||||
|
{
|
||||||
|
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
|
||||||
|
fld_name); /* purecov: inspected */
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
def= 0;
|
||||||
|
}
|
||||||
|
flags|= BLOB_FLAG;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_YEAR:
|
||||||
|
if (!fld_length || length != 2)
|
||||||
|
length= 4; /* Default length */
|
||||||
|
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_FLOAT:
|
||||||
|
/* change FLOAT(precision) to FLOAT or DOUBLE */
|
||||||
|
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
||||||
|
if (fld_length && !fld_decimals)
|
||||||
|
{
|
||||||
|
uint tmp_length= length;
|
||||||
|
if (tmp_length > PRECISION_FOR_DOUBLE)
|
||||||
|
{
|
||||||
|
my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
else if (tmp_length > PRECISION_FOR_FLOAT)
|
||||||
|
{
|
||||||
|
sql_type= FIELD_TYPE_DOUBLE;
|
||||||
|
length= DBL_DIG+7; /* -[digits].E+### */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
length= FLT_DIG+6; /* -[digits].E+## */
|
||||||
|
decimals= NOT_FIXED_DEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!fld_length && !fld_decimals)
|
||||||
|
{
|
||||||
|
length= FLT_DIG+6;
|
||||||
|
decimals= NOT_FIXED_DEC;
|
||||||
|
}
|
||||||
|
if (length < decimals &&
|
||||||
|
decimals != NOT_FIXED_DEC)
|
||||||
|
{
|
||||||
|
my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_DOUBLE:
|
||||||
|
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
||||||
|
if (!fld_length && !fld_decimals)
|
||||||
|
{
|
||||||
|
length= DBL_DIG+7;
|
||||||
|
decimals= NOT_FIXED_DEC;
|
||||||
|
}
|
||||||
|
if (length < decimals &&
|
||||||
|
decimals != NOT_FIXED_DEC)
|
||||||
|
{
|
||||||
|
my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_TIMESTAMP:
|
||||||
|
if (!fld_length)
|
||||||
|
length= 14; /* Full date YYYYMMDDHHMMSS */
|
||||||
|
else if (length != 19)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We support only even TIMESTAMP lengths less or equal than 14
|
||||||
|
and 19 as length of 4.1 compatible representation.
|
||||||
|
*/
|
||||||
|
length= ((length+1)/2)*2; /* purecov: inspected */
|
||||||
|
length= min(length,14); /* purecov: inspected */
|
||||||
|
}
|
||||||
|
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
|
||||||
|
if (fld_default_value)
|
||||||
|
{
|
||||||
|
/* Grammar allows only NOW() value for ON UPDATE clause */
|
||||||
|
if (fld_default_value->type() == Item::FUNC_ITEM &&
|
||||||
|
((Item_func*)fld_default_value)->functype() == Item_func::NOW_FUNC)
|
||||||
|
{
|
||||||
|
unireg_check= (fld_on_update_value ? Field::TIMESTAMP_DNUN_FIELD:
|
||||||
|
Field::TIMESTAMP_DN_FIELD);
|
||||||
|
/*
|
||||||
|
We don't need default value any longer moreover it is dangerous.
|
||||||
|
Everything handled by unireg_check further.
|
||||||
|
*/
|
||||||
|
def= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD:
|
||||||
|
Field::NONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
|
||||||
|
or ON UPDATE values then for the sake of compatiblity we should treat
|
||||||
|
this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
|
||||||
|
have another TIMESTAMP column with auto-set option before this one)
|
||||||
|
or DEFAULT 0 (in other cases).
|
||||||
|
So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
|
||||||
|
replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
|
||||||
|
information about all TIMESTAMP fields in table will be availiable.
|
||||||
|
|
||||||
|
If we have TIMESTAMP NULL column without explicit DEFAULT value
|
||||||
|
we treat it as having DEFAULT NULL attribute.
|
||||||
|
*/
|
||||||
|
unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD :
|
||||||
|
(flags & NOT_NULL_FLAG ? Field::TIMESTAMP_OLD_FIELD :
|
||||||
|
Field::NONE));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_DATE:
|
||||||
|
/* Old date type. */
|
||||||
|
if (protocol_version != PROTOCOL_VERSION-1)
|
||||||
|
sql_type= FIELD_TYPE_NEWDATE;
|
||||||
|
/* fall trough */
|
||||||
|
case FIELD_TYPE_NEWDATE:
|
||||||
|
length= 10;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_TIME:
|
||||||
|
length= 10;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_DATETIME:
|
||||||
|
length= 19;
|
||||||
|
break;
|
||||||
|
case FIELD_TYPE_SET:
|
||||||
|
{
|
||||||
|
if (fld_interval_list->elements > sizeof(longlong)*8)
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_BIG_SET, MYF(0), fld_name); /* purecov: inspected */
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
pack_length= get_set_pack_length(fld_interval_list->elements);
|
||||||
|
|
||||||
|
List_iterator<String> it(*fld_interval_list);
|
||||||
|
String *tmp;
|
||||||
|
while ((tmp= it++))
|
||||||
|
interval_list.push_back(tmp);
|
||||||
|
/*
|
||||||
|
Set fake length to 1 to pass the below conditions.
|
||||||
|
Real length will be set in mysql_prepare_table()
|
||||||
|
when we know the character set of the column
|
||||||
|
*/
|
||||||
|
length= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FIELD_TYPE_ENUM:
|
||||||
|
{
|
||||||
|
/* Should be safe. */
|
||||||
|
pack_length= get_enum_pack_length(fld_interval_list->elements);
|
||||||
|
|
||||||
|
List_iterator<String> it(*fld_interval_list);
|
||||||
|
String *tmp;
|
||||||
|
while ((tmp= it++))
|
||||||
|
interval_list.push_back(tmp);
|
||||||
|
length= 1; /* See comment for FIELD_TYPE_SET above. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MYSQL_TYPE_VAR_STRING:
|
||||||
|
DBUG_ASSERT(0); /* Impossible. */
|
||||||
|
break;
|
||||||
|
case MYSQL_TYPE_BIT:
|
||||||
|
{
|
||||||
|
if (!fld_length)
|
||||||
|
length= 1;
|
||||||
|
if (length > MAX_BIT_FIELD_LENGTH)
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name,
|
||||||
|
MAX_BIT_FIELD_LENGTH);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
pack_length= (length + 7) / 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FIELD_TYPE_DECIMAL:
|
||||||
|
DBUG_ASSERT(0); /* Was obsolete */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & BLOB_FLAG) &&
|
||||||
|
((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
|
||||||
|
fld_type != FIELD_TYPE_ENUM &&
|
||||||
|
(fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) ||
|
||||||
|
(!length &&
|
||||||
|
fld_type != MYSQL_TYPE_STRING &&
|
||||||
|
fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY)))
|
||||||
|
{
|
||||||
|
my_error((fld_type == MYSQL_TYPE_VAR_STRING ||
|
||||||
|
fld_type == MYSQL_TYPE_VARCHAR ||
|
||||||
|
fld_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH :
|
||||||
|
ER_TOO_BIG_DISPLAYWIDTH,
|
||||||
|
MYF(0),
|
||||||
|
fld_name, max_field_charlength); /* purecov: inspected */
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
fld_type_modifier&= AUTO_INCREMENT_FLAG;
|
||||||
|
if ((~allowed_type_modifier) & fld_type_modifier)
|
||||||
|
{
|
||||||
|
my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_RETURN(FALSE); /* success */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum_field_types get_blob_type_from_length(ulong length)
|
enum_field_types get_blob_type_from_length(ulong length)
|
||||||
{
|
{
|
||||||
enum_field_types type;
|
enum_field_types type;
|
||||||
|
|
18
sql/field.h
18
sql/field.h
|
@ -130,7 +130,19 @@ public:
|
||||||
null_bit == field->null_bit);
|
null_bit == field->null_bit);
|
||||||
}
|
}
|
||||||
virtual bool eq_def(Field *field);
|
virtual bool eq_def(Field *field);
|
||||||
|
|
||||||
|
/*
|
||||||
|
pack_length() returns size (in bytes) used to store field data in memory
|
||||||
|
(i.e. it returns the maximum size of the field in a row of the table,
|
||||||
|
which is located in RAM).
|
||||||
|
*/
|
||||||
virtual uint32 pack_length() const { return (uint32) field_length; }
|
virtual uint32 pack_length() const { return (uint32) field_length; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
pack_length_in_rec() returns size (in bytes) used to store field data on
|
||||||
|
storage (i.e. it returns the maximal size of the field in a row of the
|
||||||
|
table, which is located on disk).
|
||||||
|
*/
|
||||||
virtual uint32 pack_length_in_rec() const { return pack_length(); }
|
virtual uint32 pack_length_in_rec() const { return pack_length(); }
|
||||||
virtual uint32 sort_length() const { return pack_length(); }
|
virtual uint32 sort_length() const { return pack_length(); }
|
||||||
virtual void reset(void) { bzero(ptr,pack_length()); }
|
virtual void reset(void) { bzero(ptr,pack_length()); }
|
||||||
|
@ -1395,6 +1407,12 @@ public:
|
||||||
void init_for_tmp_table(enum_field_types sql_type_arg,
|
void init_for_tmp_table(enum_field_types sql_type_arg,
|
||||||
uint32 max_length, uint32 decimals,
|
uint32 max_length, uint32 decimals,
|
||||||
bool maybe_null, bool is_unsigned);
|
bool maybe_null, bool is_unsigned);
|
||||||
|
|
||||||
|
bool init(THD *thd, char *field_name, enum_field_types type, char *length,
|
||||||
|
char *decimals, uint type_modifier, Item *default_value,
|
||||||
|
Item *on_update_value, LEX_STRING *comment, char *change,
|
||||||
|
List<String> *interval_list, CHARSET_INFO *cs,
|
||||||
|
uint uint_geom_type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
197
sql/item.cc
197
sql/item.cc
|
@ -296,23 +296,6 @@ longlong Item::val_int_from_decimal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *Item::operator new(size_t size, Item *reuse, uint *rsize)
|
|
||||||
{
|
|
||||||
if (reuse && size <= reuse->rsize)
|
|
||||||
{
|
|
||||||
if (rsize)
|
|
||||||
(*rsize)= reuse->rsize;
|
|
||||||
reuse->cleanup();
|
|
||||||
delete reuse;
|
|
||||||
TRASH((void *)reuse, size);
|
|
||||||
return (void *)reuse;
|
|
||||||
}
|
|
||||||
if (rsize)
|
|
||||||
(*rsize)= (uint) size;
|
|
||||||
return (void *)sql_alloc((uint)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Item::Item():
|
Item::Item():
|
||||||
rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
|
rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
|
||||||
is_autogenerated_name(TRUE),
|
is_autogenerated_name(TRUE),
|
||||||
|
@ -802,9 +785,41 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
Item_splocal methods
|
Item_sp_variable methods
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
double Item_splocal::val_real()
|
|
||||||
|
Item_sp_variable::Item_sp_variable(char *sp_var_name_str,
|
||||||
|
uint sp_var_name_length)
|
||||||
|
:m_thd(0)
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
, m_sp(0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
m_name.str= sp_var_name_str;
|
||||||
|
m_name.length= sp_var_name_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Item_sp_variable::fix_fields(THD *thd, Item **)
|
||||||
|
{
|
||||||
|
Item *it;
|
||||||
|
|
||||||
|
m_thd= thd; /* NOTE: this must be set before any this_xxx() */
|
||||||
|
it= this_item();
|
||||||
|
|
||||||
|
DBUG_ASSERT(it->fixed);
|
||||||
|
|
||||||
|
max_length= it->max_length;
|
||||||
|
decimals= it->decimals;
|
||||||
|
unsigned_flag= it->unsigned_flag;
|
||||||
|
fixed= 1;
|
||||||
|
collation.set(it->collation.collation, it->collation.derivation);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double Item_sp_variable::val_real()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
Item *it= this_item();
|
Item *it= this_item();
|
||||||
|
@ -814,7 +829,7 @@ double Item_splocal::val_real()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
longlong Item_splocal::val_int()
|
longlong Item_sp_variable::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
Item *it= this_item();
|
Item *it= this_item();
|
||||||
|
@ -824,13 +839,14 @@ longlong Item_splocal::val_int()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String *Item_splocal::val_str(String *sp)
|
String *Item_sp_variable::val_str(String *sp)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
Item *it= this_item();
|
Item *it= this_item();
|
||||||
String *res= it->val_str(sp);
|
String *res= it->val_str(sp);
|
||||||
|
|
||||||
null_value= it->null_value;
|
null_value= it->null_value;
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -854,11 +870,12 @@ String *Item_splocal::val_str(String *sp)
|
||||||
str_value.set(res->ptr(), res->length(), res->charset());
|
str_value.set(res->ptr(), res->length(), res->charset());
|
||||||
else
|
else
|
||||||
res->mark_as_const();
|
res->mark_as_const();
|
||||||
|
|
||||||
return &str_value;
|
return &str_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
|
my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed);
|
DBUG_ASSERT(fixed);
|
||||||
Item *it= this_item();
|
Item *it= this_item();
|
||||||
|
@ -868,64 +885,53 @@ my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_splocal::is_null()
|
bool Item_sp_variable::is_null()
|
||||||
{
|
{
|
||||||
Item *it= this_item();
|
return this_item()->is_null();
|
||||||
return it->is_null();
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Item_splocal methods
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
|
||||||
|
uint sp_var_idx,
|
||||||
|
enum_field_types sp_var_type,
|
||||||
|
uint pos_in_q)
|
||||||
|
:Item_sp_variable(sp_var_name.str, sp_var_name.length),
|
||||||
|
m_var_idx(sp_var_idx), pos_in_query(pos_in_q)
|
||||||
|
{
|
||||||
|
maybe_null= TRUE;
|
||||||
|
|
||||||
|
m_type= sp_map_item_type(sp_var_type);
|
||||||
|
m_result_type= sp_map_result_type(sp_var_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Item *
|
Item *
|
||||||
Item_splocal::this_item()
|
Item_splocal::this_item()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(owner == thd->spcont->owner);
|
DBUG_ASSERT(m_sp == m_thd->spcont->sp);
|
||||||
return thd->spcont->get_item(m_offset);
|
|
||||||
|
return m_thd->spcont->get_item(m_var_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Item *
|
||||||
|
Item_splocal::this_item() const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(m_sp == m_thd->spcont->sp);
|
||||||
|
|
||||||
|
return m_thd->spcont->get_item(m_var_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Item **
|
Item **
|
||||||
Item_splocal::this_item_addr(THD *thd, Item **addr)
|
Item_splocal::this_item_addr(THD *thd, Item **)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(owner == thd->spcont->owner);
|
DBUG_ASSERT(m_sp == thd->spcont->sp);
|
||||||
return thd->spcont->get_item_addr(m_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
Item *
|
return thd->spcont->get_item_addr(m_var_idx);
|
||||||
Item_splocal::this_const_item() const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(owner == thd->spcont->owner);
|
|
||||||
return thd->spcont->get_item(m_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
Item::Type
|
|
||||||
Item_splocal::type() const
|
|
||||||
{
|
|
||||||
if (thd && thd->spcont)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(owner == thd->spcont->owner);
|
|
||||||
return thd->spcont->get_item(m_offset)->type();
|
|
||||||
}
|
|
||||||
return NULL_ITEM; // Anything but SUBSELECT_ITEM
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Item_splocal::fix_fields(THD *thd_arg, Item **ref)
|
|
||||||
{
|
|
||||||
Item *it;
|
|
||||||
thd= thd_arg; // Must be set before this_item()
|
|
||||||
it= this_item();
|
|
||||||
DBUG_ASSERT(it->fixed);
|
|
||||||
max_length= it->max_length;
|
|
||||||
decimals= it->decimals;
|
|
||||||
unsigned_flag= it->unsigned_flag;
|
|
||||||
fixed= 1;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Item_splocal::cleanup()
|
|
||||||
{
|
|
||||||
fixed= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -934,7 +940,53 @@ void Item_splocal::print(String *str)
|
||||||
str->reserve(m_name.length+8);
|
str->reserve(m_name.length+8);
|
||||||
str->append(m_name.str, m_name.length);
|
str->append(m_name.str, m_name.length);
|
||||||
str->append('@');
|
str->append('@');
|
||||||
str->qs_append(m_offset);
|
str->qs_append(m_var_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Item_case_expr methods
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
Item_case_expr::Item_case_expr(int case_expr_id)
|
||||||
|
:Item_sp_variable(STRING_WITH_LEN("case_expr")),
|
||||||
|
m_case_expr_id(case_expr_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item *
|
||||||
|
Item_case_expr::this_item()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(m_sp == m_thd->spcont->sp);
|
||||||
|
|
||||||
|
return m_thd->spcont->get_case_expr(m_case_expr_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const Item *
|
||||||
|
Item_case_expr::this_item() const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(m_sp == m_thd->spcont->sp);
|
||||||
|
|
||||||
|
return m_thd->spcont->get_case_expr(m_case_expr_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item **
|
||||||
|
Item_case_expr::this_item_addr(THD *thd, Item **)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(m_sp == thd->spcont->sp);
|
||||||
|
|
||||||
|
return thd->spcont->get_case_expr_addr(m_case_expr_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_case_expr::print(String *str)
|
||||||
|
{
|
||||||
|
str->append(STRING_WITH_LEN("case_expr@"));
|
||||||
|
str->qs_append(m_case_expr_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1013,12 +1065,6 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_name_const::cleanup()
|
|
||||||
{
|
|
||||||
fixed= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Item_name_const::print(String *str)
|
void Item_name_const::print(String *str)
|
||||||
{
|
{
|
||||||
str->append(STRING_WITH_LEN("NAME_CONST("));
|
str->append(STRING_WITH_LEN("NAME_CONST("));
|
||||||
|
@ -3911,6 +3957,9 @@ int Item::save_in_field(Field *field, bool no_conversions)
|
||||||
str_value.set_quick(0, 0, cs);
|
str_value.set_quick(0, 0, cs);
|
||||||
return set_field_to_null_with_conversions(field, no_conversions);
|
return set_field_to_null_with_conversions(field, no_conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NOTE: If null_value == FALSE, "result" must be not NULL. */
|
||||||
|
|
||||||
field->set_notnull();
|
field->set_notnull();
|
||||||
error=field->store(result->ptr(),result->length(),cs);
|
error=field->store(result->ptr(),result->length(),cs);
|
||||||
str_value.set_quick(0, 0, cs);
|
str_value.set_quick(0, 0, cs);
|
||||||
|
|
249
sql/item.h
249
sql/item.h
|
@ -383,8 +383,6 @@ public:
|
||||||
{ return (void*) sql_alloc((uint) size); }
|
{ return (void*) sql_alloc((uint) size); }
|
||||||
static void *operator new(size_t size, MEM_ROOT *mem_root)
|
static void *operator new(size_t size, MEM_ROOT *mem_root)
|
||||||
{ return (void*) alloc_root(mem_root, (uint) size); }
|
{ return (void*) alloc_root(mem_root, (uint) size); }
|
||||||
/* Special for SP local variable assignment - reusing slots */
|
|
||||||
static void *operator new(size_t size, Item *reuse, uint *rsize);
|
|
||||||
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
|
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
|
||||||
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
|
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
|
||||||
|
|
||||||
|
@ -713,13 +711,13 @@ public:
|
||||||
current value and pointer to current Item otherwise.
|
current value and pointer to current Item otherwise.
|
||||||
*/
|
*/
|
||||||
virtual Item *this_item() { return this; }
|
virtual Item *this_item() { return this; }
|
||||||
|
virtual const Item *this_item() const { return this; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For SP local variable returns address of pointer to Item representing its
|
For SP local variable returns address of pointer to Item representing its
|
||||||
current value and pointer passed via parameter otherwise.
|
current value and pointer passed via parameter otherwise.
|
||||||
*/
|
*/
|
||||||
virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
|
virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
|
||||||
/* For SPs mostly. */
|
|
||||||
virtual Item *this_const_item() const { return const_cast<Item*>(this); }
|
|
||||||
|
|
||||||
// Row emulation
|
// Row emulation
|
||||||
virtual uint cols() { return 1; }
|
virtual uint cols() { return 1; }
|
||||||
|
@ -748,21 +746,32 @@ public:
|
||||||
|
|
||||||
class sp_head;
|
class sp_head;
|
||||||
|
|
||||||
/*
|
|
||||||
A reference to local SP variable (incl. reference to SP parameter), used in
|
|
||||||
runtime.
|
|
||||||
|
|
||||||
NOTE
|
|
||||||
This item has a "value" item, defined as
|
|
||||||
this_item() = thd->spcont->get_item(m_offset)
|
|
||||||
and it delegates everything to that item (if !this_item() then this item
|
|
||||||
poses as Item_null) except for name, which is the name of SP local
|
|
||||||
variable.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Item_splocal : public Item
|
/*****************************************************************************
|
||||||
|
The class is a base class for representation of stored routine variables in
|
||||||
|
the Item-hierarchy. There are the following kinds of SP-vars:
|
||||||
|
- local variables (Item_splocal);
|
||||||
|
- CASE expression (Item_case_expr);
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
class Item_sp_variable :public Item
|
||||||
{
|
{
|
||||||
uint m_offset;
|
protected:
|
||||||
|
/*
|
||||||
|
THD, which is stored in fix_fields() and is used in this_item() to avoid
|
||||||
|
current_thd use.
|
||||||
|
*/
|
||||||
|
THD *m_thd;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LEX_STRING m_name;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Buffer, pointing to the string value of the item. We need it to
|
||||||
|
protect internal buffer from changes. See comment to analogous
|
||||||
|
member in Item_param for more details.
|
||||||
|
*/
|
||||||
|
String str_value_ptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
|
@ -770,11 +779,74 @@ public:
|
||||||
Routine to which this Item_splocal belongs. Used for checking if correct
|
Routine to which this Item_splocal belongs. Used for checking if correct
|
||||||
runtime context is used for variable handling.
|
runtime context is used for variable handling.
|
||||||
*/
|
*/
|
||||||
sp_head *owner;
|
sp_head *m_sp;
|
||||||
#endif
|
#endif
|
||||||
LEX_STRING m_name;
|
|
||||||
THD *thd;
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
Item_sp_variable(char *sp_var_name_str, uint sp_var_name_length);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool fix_fields(THD *thd, Item **);
|
||||||
|
|
||||||
|
double val_real();
|
||||||
|
longlong val_int();
|
||||||
|
String *val_str(String *sp);
|
||||||
|
my_decimal *val_decimal(my_decimal *decimal_value);
|
||||||
|
bool is_null();
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline void make_field(Send_field *field);
|
||||||
|
|
||||||
|
inline bool const_item() const;
|
||||||
|
|
||||||
|
inline int save_in_field(Field *field, bool no_conversions);
|
||||||
|
inline bool send(Protocol *protocol, String *str);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Item_sp_variable inline implementation.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
inline void Item_sp_variable::make_field(Send_field *field)
|
||||||
|
{
|
||||||
|
Item *it= this_item();
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
it->set_name(name, (uint) strlen(name), system_charset_info);
|
||||||
|
else
|
||||||
|
it->set_name(m_name.str, m_name.length, system_charset_info);
|
||||||
|
it->make_field(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Item_sp_variable::const_item() const
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Item_sp_variable::save_in_field(Field *field, bool no_conversions)
|
||||||
|
{
|
||||||
|
return this_item()->save_in_field(field, no_conversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Item_sp_variable::send(Protocol *protocol, String *str)
|
||||||
|
{
|
||||||
|
return this_item()->send(protocol, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
A reference to local SP variable (incl. reference to SP parameter), used in
|
||||||
|
runtime.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
class Item_splocal :public Item_sp_variable
|
||||||
|
{
|
||||||
|
uint m_var_idx;
|
||||||
|
|
||||||
|
Type m_type;
|
||||||
|
Item_result m_result_type;
|
||||||
|
|
||||||
|
public:
|
||||||
/*
|
/*
|
||||||
Position of this reference to SP variable in the statement (the
|
Position of this reference to SP variable in the statement (the
|
||||||
statement itself is in sp_instr_stmt::m_query).
|
statement itself is in sp_instr_stmt::m_query).
|
||||||
|
@ -787,78 +859,94 @@ public:
|
||||||
*/
|
*/
|
||||||
uint pos_in_query;
|
uint pos_in_query;
|
||||||
|
|
||||||
Item_splocal(LEX_STRING name, uint offset, uint pos_in_q=0)
|
Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx,
|
||||||
: m_offset(offset), m_name(name), thd(0), pos_in_query(pos_in_q)
|
enum_field_types sp_var_type, uint pos_in_q= 0);
|
||||||
{
|
|
||||||
maybe_null= TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For error printing */
|
|
||||||
inline LEX_STRING *my_name(LEX_STRING *get_name)
|
|
||||||
{
|
|
||||||
if (!get_name)
|
|
||||||
return &m_name;
|
|
||||||
(*get_name)= m_name;
|
|
||||||
return get_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_splocal() { return 1; } /* Needed for error checking */
|
bool is_splocal() { return 1; } /* Needed for error checking */
|
||||||
|
|
||||||
Item *this_item();
|
Item *this_item();
|
||||||
|
const Item *this_item() const;
|
||||||
Item **this_item_addr(THD *thd, Item **);
|
Item **this_item_addr(THD *thd, Item **);
|
||||||
Item *this_const_item() const;
|
|
||||||
|
|
||||||
bool fix_fields(THD *, Item **);
|
|
||||||
void cleanup();
|
|
||||||
|
|
||||||
inline uint get_offset()
|
|
||||||
{
|
|
||||||
return m_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abstract methods inherited from Item. Just defer the call to
|
|
||||||
// the item in the frame
|
|
||||||
enum Type type() const;
|
|
||||||
|
|
||||||
double val_real();
|
|
||||||
longlong val_int();
|
|
||||||
String *val_str(String *sp);
|
|
||||||
my_decimal *val_decimal(my_decimal *);
|
|
||||||
bool is_null();
|
|
||||||
void print(String *str);
|
void print(String *str);
|
||||||
|
|
||||||
void make_field(Send_field *field)
|
public:
|
||||||
{
|
inline const LEX_STRING *my_name() const;
|
||||||
Item *it= this_item();
|
|
||||||
|
|
||||||
if (name)
|
inline uint get_var_idx() const;
|
||||||
it->set_name(name, (uint) strlen(name), system_charset_info);
|
|
||||||
else
|
|
||||||
it->set_name(m_name.str, m_name.length, system_charset_info);
|
|
||||||
it->make_field(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
Item_result result_type() const
|
inline enum Type type() const;
|
||||||
{
|
inline Item_result result_type() const;
|
||||||
return this_const_item()->result_type();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool const_item() const
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int save_in_field(Field *field, bool no_conversions)
|
|
||||||
{
|
|
||||||
return this_item()->save_in_field(field, no_conversions);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool send(Protocol *protocol, String *str)
|
|
||||||
{
|
|
||||||
return this_item()->send(protocol, str);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Item_splocal inline implementation.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
inline const LEX_STRING *Item_splocal::my_name() const
|
||||||
|
{
|
||||||
|
return &m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint Item_splocal::get_var_idx() const
|
||||||
|
{
|
||||||
|
return m_var_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline enum Item::Type Item_splocal::type() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Item_result Item_splocal::result_type() const
|
||||||
|
{
|
||||||
|
return m_result_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
A reference to case expression in SP, used in runtime.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
class Item_case_expr :public Item_sp_variable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Item_case_expr(int case_expr_id);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Item *this_item();
|
||||||
|
const Item *this_item() const;
|
||||||
|
Item **this_item_addr(THD *thd, Item **);
|
||||||
|
|
||||||
|
inline enum Type type() const;
|
||||||
|
inline Item_result result_type() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
NOTE: print() is intended to be used from views and for debug.
|
||||||
|
Item_case_expr can not occur in views, so here it is only for debug
|
||||||
|
purposes.
|
||||||
|
*/
|
||||||
|
void print(String *str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_case_expr_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
Item_case_expr inline implementation.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
inline enum Item::Type Item_case_expr::type() const
|
||||||
|
{
|
||||||
|
return this_item()->type();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Item_result Item_case_expr::result_type() const
|
||||||
|
{
|
||||||
|
return this_item()->result_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NAME_CONST(given_name, const_value).
|
NAME_CONST(given_name, const_value).
|
||||||
|
@ -885,7 +973,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fix_fields(THD *, Item **);
|
bool fix_fields(THD *, Item **);
|
||||||
void cleanup();
|
|
||||||
|
|
||||||
enum Type type() const;
|
enum Type type() const;
|
||||||
double val_real();
|
double val_real();
|
||||||
|
|
|
@ -4716,7 +4716,7 @@ Item_func_sp::sp_result_field(void) const
|
||||||
share->table_cache_key = empty_name;
|
share->table_cache_key = empty_name;
|
||||||
share->table_name = empty_name;
|
share->table_name = empty_name;
|
||||||
}
|
}
|
||||||
field= m_sp->make_field(max_length, name, dummy_table);
|
field= m_sp->create_result_field(max_length, name, dummy_table);
|
||||||
DBUG_RETURN(field);
|
DBUG_RETURN(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4729,17 +4729,17 @@ Item_func_sp::sp_result_field(void) const
|
||||||
1 value = NULL or error
|
1 value = NULL or error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
bool
|
||||||
Item_func_sp::execute(Field **flp)
|
Item_func_sp::execute(Field **flp)
|
||||||
{
|
{
|
||||||
Item *it;
|
THD *thd= current_thd;
|
||||||
Field *f;
|
Field *f;
|
||||||
if (execute(&it))
|
|
||||||
{
|
/*
|
||||||
null_value= 1;
|
Get field in virtual tmp table to store result. Create the field if
|
||||||
context->process_error(current_thd);
|
invoked first time.
|
||||||
return 1;
|
*/
|
||||||
}
|
|
||||||
if (!(f= *flp))
|
if (!(f= *flp))
|
||||||
{
|
{
|
||||||
*flp= f= sp_result_field();
|
*flp= f= sp_result_field();
|
||||||
|
@ -4748,20 +4748,33 @@ Item_func_sp::execute(Field **flp)
|
||||||
f->null_ptr= (uchar *)&null_value;
|
f->null_ptr= (uchar *)&null_value;
|
||||||
f->null_bit= 1;
|
f->null_bit= 1;
|
||||||
}
|
}
|
||||||
it->save_in_field(f, 1);
|
|
||||||
return null_value= f->is_null();
|
/* Execute function and store the return value in the field. */
|
||||||
|
|
||||||
|
if (execute_impl(thd, f))
|
||||||
|
{
|
||||||
|
null_value= 1;
|
||||||
|
context->process_error(thd);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the field (the value) is not NULL. */
|
||||||
|
|
||||||
|
null_value= f->is_null();
|
||||||
|
|
||||||
|
return null_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
bool
|
||||||
Item_func_sp::execute(Item **itp)
|
Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Item_func_sp::execute");
|
bool err_status= TRUE;
|
||||||
THD *thd= current_thd;
|
|
||||||
int res= -1;
|
|
||||||
Sub_statement_state statement_state;
|
Sub_statement_state statement_state;
|
||||||
Security_context *save_security_ctx= thd->security_ctx, *save_ctx_func;
|
Security_context *save_security_ctx= thd->security_ctx, *save_ctx_func;
|
||||||
|
|
||||||
|
DBUG_ENTER("Item_func_sp::execute_impl");
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (context->security_ctx)
|
if (context->security_ctx)
|
||||||
{
|
{
|
||||||
|
@ -4778,7 +4791,7 @@ Item_func_sp::execute(Item **itp)
|
||||||
function call into binlog.
|
function call into binlog.
|
||||||
*/
|
*/
|
||||||
thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
|
thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
|
||||||
res= m_sp->execute_function(thd, args, arg_count, itp);
|
err_status= m_sp->execute_function(thd, args, arg_count, return_value_fld);
|
||||||
thd->restore_sub_statement_state(&statement_state);
|
thd->restore_sub_statement_state(&statement_state);
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
@ -4788,7 +4801,7 @@ error:
|
||||||
#else
|
#else
|
||||||
error:
|
error:
|
||||||
#endif
|
#endif
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(err_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4884,7 +4897,7 @@ Item_func_sp::tmp_table_field(TABLE *t_arg)
|
||||||
DBUG_ENTER("Item_func_sp::tmp_table_field");
|
DBUG_ENTER("Item_func_sp::tmp_table_field");
|
||||||
|
|
||||||
if (m_sp)
|
if (m_sp)
|
||||||
res= m_sp->make_field(max_length, (const char *)name, t_arg);
|
res= m_sp->create_result_field(max_length, (const char*) name, t_arg);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
res= Item_func::tmp_table_field(t_arg);
|
res= Item_func::tmp_table_field(t_arg);
|
||||||
|
|
|
@ -1374,8 +1374,8 @@ private:
|
||||||
Field *result_field;
|
Field *result_field;
|
||||||
char result_buf[64];
|
char result_buf[64];
|
||||||
|
|
||||||
int execute(Item **itp);
|
bool execute(Field **flp);
|
||||||
int execute(Field **flp);
|
bool execute_impl(THD *thd, Field *return_value_fld);
|
||||||
Field *sp_result_field(void) const;
|
Field *sp_result_field(void) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -660,6 +660,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
|
||||||
bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
|
bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
|
||||||
int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
|
int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
|
||||||
KEY_CACHE *dst_cache);
|
KEY_CACHE *dst_cache);
|
||||||
|
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
|
||||||
|
|
||||||
bool mysql_xa_recover(THD *thd);
|
bool mysql_xa_recover(THD *thd);
|
||||||
|
|
||||||
|
@ -1099,8 +1100,8 @@ void unhex_type2(TYPELIB *lib);
|
||||||
uint check_word(TYPELIB *lib, const char *val, const char *end,
|
uint check_word(TYPELIB *lib, const char *val, const char *end,
|
||||||
const char **end_of_word);
|
const char **end_of_word);
|
||||||
|
|
||||||
bool is_keyword(const char *name, uint len);
|
|
||||||
|
|
||||||
|
bool is_keyword(const char *name, uint len);
|
||||||
|
|
||||||
#define MY_DB_OPT_FILE "db.opt"
|
#define MY_DB_OPT_FILE "db.opt"
|
||||||
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
|
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
|
||||||
|
|
|
@ -467,7 +467,7 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
|
||||||
bzero(&table, sizeof(table));
|
bzero(&table, sizeof(table));
|
||||||
table.in_use= thd;
|
table.in_use= thd;
|
||||||
table.s = &table.share_not_to_be_used;
|
table.s = &table.share_not_to_be_used;
|
||||||
field= sp->make_field(0, 0, &table);
|
field= sp->create_result_field(0, 0, &table);
|
||||||
field->sql_type(result);
|
field->sql_type(result);
|
||||||
delete field;
|
delete field;
|
||||||
}
|
}
|
||||||
|
|
949
sql/sp_head.cc
949
sql/sp_head.cc
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,9 @@
|
||||||
Item_result
|
Item_result
|
||||||
sp_map_result_type(enum enum_field_types type);
|
sp_map_result_type(enum enum_field_types type);
|
||||||
|
|
||||||
|
Item::Type
|
||||||
|
sp_map_item_type(enum enum_field_types type);
|
||||||
|
|
||||||
uint
|
uint
|
||||||
sp_get_flags_for_command(LEX *lex);
|
sp_get_flags_for_command(LEX *lex);
|
||||||
|
|
||||||
|
@ -123,12 +126,9 @@ public:
|
||||||
/* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
|
/* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
|
||||||
int m_type;
|
int m_type;
|
||||||
uint m_flags; // Boolean attributes of a stored routine
|
uint m_flags; // Boolean attributes of a stored routine
|
||||||
enum enum_field_types m_returns; // For FUNCTIONs only
|
|
||||||
Field::geometry_type m_geom_returns;
|
create_field m_return_field_def; /* This is used for FUNCTIONs only. */
|
||||||
CHARSET_INFO *m_returns_cs; // For FUNCTIONs only
|
|
||||||
TYPELIB *m_returns_typelib; // For FUNCTIONs only
|
|
||||||
uint m_returns_len; // For FUNCTIONs only
|
|
||||||
uint m_returns_pack; // For FUNCTIONs only
|
|
||||||
uchar *m_tmp_query; // Temporary pointer to sub query string
|
uchar *m_tmp_query; // Temporary pointer to sub query string
|
||||||
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
|
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
|
||||||
st_sp_chistics *m_chistics;
|
st_sp_chistics *m_chistics;
|
||||||
|
@ -202,9 +202,6 @@ public:
|
||||||
void
|
void
|
||||||
init_strings(THD *thd, LEX *lex, sp_name *name);
|
init_strings(THD *thd, LEX *lex, sp_name *name);
|
||||||
|
|
||||||
TYPELIB *
|
|
||||||
create_typelib(List<String> *src);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
create(THD *thd);
|
create(THD *thd);
|
||||||
|
|
||||||
|
@ -214,10 +211,10 @@ public:
|
||||||
void
|
void
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
int
|
bool
|
||||||
execute_function(THD *thd, Item **args, uint argcount, Item **resp);
|
execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
|
||||||
|
|
||||||
int
|
bool
|
||||||
execute_procedure(THD *thd, List<Item> *args);
|
execute_procedure(THD *thd, List<Item> *args);
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -278,7 +275,12 @@ public:
|
||||||
|
|
||||||
char *create_string(THD *thd, ulong *lenp);
|
char *create_string(THD *thd, ulong *lenp);
|
||||||
|
|
||||||
Field *make_field(uint max_length, const char *name, TABLE *dummy);
|
Field *create_result_field(uint field_max_length, const char *field_name,
|
||||||
|
TABLE *table);
|
||||||
|
|
||||||
|
bool fill_field_definition(THD *thd, LEX *lex,
|
||||||
|
enum enum_field_types field_type,
|
||||||
|
create_field *field_def);
|
||||||
|
|
||||||
void set_info(longlong created, longlong modified,
|
void set_info(longlong created, longlong modified,
|
||||||
st_sp_chistics *chistics, ulong sql_mode);
|
st_sp_chistics *chistics, ulong sql_mode);
|
||||||
|
@ -363,7 +365,7 @@ private:
|
||||||
*/
|
*/
|
||||||
HASH m_sptabs;
|
HASH m_sptabs;
|
||||||
|
|
||||||
int
|
bool
|
||||||
execute(THD *thd);
|
execute(THD *thd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1074,6 +1076,31 @@ private:
|
||||||
}; // class sp_instr_error : public sp_instr
|
}; // class sp_instr_error : public sp_instr
|
||||||
|
|
||||||
|
|
||||||
|
class sp_instr_set_case_expr :public sp_instr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
sp_instr_set_case_expr(uint ip, sp_pcontext *ctx, uint case_expr_id,
|
||||||
|
Item *case_expr, LEX *lex)
|
||||||
|
:sp_instr(ip, ctx), m_case_expr_id(case_expr_id), m_case_expr(case_expr),
|
||||||
|
m_lex_keeper(lex, TRUE)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual int execute(THD *thd, uint *nextp);
|
||||||
|
|
||||||
|
virtual int exec_core(THD *thd, uint *nextp);
|
||||||
|
|
||||||
|
virtual void print(String *str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint m_case_expr_id;
|
||||||
|
Item *m_case_expr;
|
||||||
|
sp_lex_keeper m_lex_keeper;
|
||||||
|
|
||||||
|
}; // class sp_instr_set_case_expr : public sp_instr
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
bool
|
bool
|
||||||
sp_change_security_context(THD *thd, sp_head *sp,
|
sp_change_security_context(THD *thd, sp_head *sp,
|
||||||
|
@ -1086,8 +1113,10 @@ TABLE_LIST *
|
||||||
sp_add_to_query_tables(THD *thd, LEX *lex,
|
sp_add_to_query_tables(THD *thd, LEX *lex,
|
||||||
const char *db, const char *name,
|
const char *db, const char *name,
|
||||||
thr_lock_type locktype);
|
thr_lock_type locktype);
|
||||||
|
Item *
|
||||||
|
sp_prepare_func_item(THD* thd, Item **it_addr);
|
||||||
|
|
||||||
Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
|
bool
|
||||||
Item *reuse, bool use_callers_arena);
|
sp_eval_expr(THD *thd, Field *result_field, Item *expr_item);
|
||||||
|
|
||||||
#endif /* _SP_HEAD_H_ */
|
#endif /* _SP_HEAD_H_ */
|
||||||
|
|
|
@ -51,21 +51,26 @@ sp_cond_check(LEX_STRING *sqlstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_pcontext::sp_pcontext(sp_pcontext *prev)
|
sp_pcontext::sp_pcontext(sp_pcontext *prev)
|
||||||
: Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
|
:Sql_alloc(), m_total_pvars(0), m_csubsize(0), m_hsubsize(0),
|
||||||
m_handlers(0), m_parent(prev), m_pboundary(0)
|
m_handlers(0), m_parent(prev), m_pboundary(0)
|
||||||
{
|
{
|
||||||
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
|
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
|
||||||
|
VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int), 16, 8));
|
||||||
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
|
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
|
||||||
VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8));
|
VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8));
|
||||||
VOID(my_init_dynamic_array(&m_handler, sizeof(sp_cond_type_t *), 16, 8));
|
VOID(my_init_dynamic_array(&m_handler, sizeof(sp_cond_type_t *), 16, 8));
|
||||||
m_label.empty();
|
m_label.empty();
|
||||||
m_children.empty();
|
m_children.empty();
|
||||||
if (!prev)
|
if (!prev)
|
||||||
|
{
|
||||||
m_poffset= m_coffset= 0;
|
m_poffset= m_coffset= 0;
|
||||||
|
m_num_case_exprs= 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_poffset= prev->current_pvars();
|
m_poffset= prev->m_poffset + prev->m_total_pvars;
|
||||||
m_coffset= prev->current_cursors();
|
m_coffset= prev->current_cursors();
|
||||||
|
m_num_case_exprs= prev->get_num_case_exprs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +86,7 @@ sp_pcontext::destroy()
|
||||||
m_children.empty();
|
m_children.empty();
|
||||||
m_label.empty();
|
m_label.empty();
|
||||||
delete_dynamic(&m_pvar);
|
delete_dynamic(&m_pvar);
|
||||||
|
delete_dynamic(&m_case_expr_id_lst);
|
||||||
delete_dynamic(&m_cond);
|
delete_dynamic(&m_cond);
|
||||||
delete_dynamic(&m_cursor);
|
delete_dynamic(&m_cursor);
|
||||||
delete_dynamic(&m_handler);
|
delete_dynamic(&m_handler);
|
||||||
|
@ -99,16 +105,19 @@ sp_pcontext::push_context()
|
||||||
sp_pcontext *
|
sp_pcontext *
|
||||||
sp_pcontext::pop_context()
|
sp_pcontext::pop_context()
|
||||||
{
|
{
|
||||||
uint submax= max_pvars();
|
m_parent->m_total_pvars= m_parent->m_total_pvars + m_total_pvars;
|
||||||
|
|
||||||
if (submax > m_parent->m_psubsize)
|
uint submax= max_handlers();
|
||||||
m_parent->m_psubsize= submax;
|
|
||||||
submax= max_handlers();
|
|
||||||
if (submax > m_parent->m_hsubsize)
|
if (submax > m_parent->m_hsubsize)
|
||||||
m_parent->m_hsubsize= submax;
|
m_parent->m_hsubsize= submax;
|
||||||
|
|
||||||
submax= max_cursors();
|
submax= max_cursors();
|
||||||
if (submax > m_parent->m_csubsize)
|
if (submax > m_parent->m_csubsize)
|
||||||
m_parent->m_csubsize= submax;
|
m_parent->m_csubsize= submax;
|
||||||
|
|
||||||
|
if (m_num_case_exprs > m_parent->m_num_case_exprs)
|
||||||
|
m_parent->m_num_case_exprs= m_num_case_exprs;
|
||||||
|
|
||||||
return m_parent;
|
return m_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,26 +200,29 @@ sp_pcontext::find_pvar(uint offset)
|
||||||
return NULL; // index out of bounds
|
return NULL; // index out of bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
sp_pvar_t *
|
||||||
sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type,
|
sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type,
|
||||||
sp_param_mode_t mode)
|
sp_param_mode_t mode)
|
||||||
{
|
{
|
||||||
sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
|
sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
|
||||||
|
|
||||||
if (p)
|
if (!p)
|
||||||
{
|
return NULL;
|
||||||
if (m_pvar.elements == m_psubsize)
|
|
||||||
m_psubsize+= 1;
|
++m_total_pvars;
|
||||||
p->name.str= name->str;
|
|
||||||
p->name.length= name->length;
|
p->name.str= name->str;
|
||||||
p->type= type;
|
p->name.length= name->length;
|
||||||
p->mode= mode;
|
p->type= type;
|
||||||
p->offset= current_pvars();
|
p->mode= mode;
|
||||||
p->dflt= NULL;
|
p->offset= current_pvars();
|
||||||
insert_dynamic(&m_pvar, (gptr)&p);
|
p->dflt= NULL;
|
||||||
}
|
insert_dynamic(&m_pvar, (gptr)&p);
|
||||||
|
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sp_label_t *
|
sp_label_t *
|
||||||
sp_pcontext::push_label(char *name, uint ip)
|
sp_pcontext::push_label(char *name, uint ip)
|
||||||
{
|
{
|
||||||
|
@ -354,6 +366,29 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_pcontext::retrieve_field_definitions(List<create_field> *field_def_lst)
|
||||||
|
{
|
||||||
|
/* Put local/context fields in the result list. */
|
||||||
|
|
||||||
|
for (uint i = 0; i < m_pvar.elements; ++i)
|
||||||
|
{
|
||||||
|
sp_pvar_t *var_def;
|
||||||
|
get_dynamic(&m_pvar, (gptr) &var_def, i);
|
||||||
|
|
||||||
|
field_def_lst->push_back(&var_def->field_def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put the fields of the enclosed contexts in the result list. */
|
||||||
|
|
||||||
|
List_iterator_fast<sp_pcontext> li(m_children);
|
||||||
|
sp_pcontext *ctx;
|
||||||
|
|
||||||
|
while ((ctx = li++))
|
||||||
|
ctx->retrieve_field_definitions(field_def_lst);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find a cursor by offset from the top.
|
Find a cursor by offset from the top.
|
||||||
This is only used for debugging.
|
This is only used for debugging.
|
||||||
|
|
|
@ -34,8 +34,16 @@ typedef struct sp_pvar
|
||||||
LEX_STRING name;
|
LEX_STRING name;
|
||||||
enum enum_field_types type;
|
enum enum_field_types type;
|
||||||
sp_param_mode_t mode;
|
sp_param_mode_t mode;
|
||||||
uint offset; // Offset in current frame
|
|
||||||
|
/*
|
||||||
|
offset -- basically, this is an index of variable in the scope of root
|
||||||
|
parsing context. This means, that all variables in a stored routine
|
||||||
|
have distinct indexes/offsets.
|
||||||
|
*/
|
||||||
|
uint offset;
|
||||||
|
|
||||||
Item *dflt;
|
Item *dflt;
|
||||||
|
create_field field_def;
|
||||||
} sp_pvar_t;
|
} sp_pvar_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,9 +122,9 @@ class sp_pcontext : public Sql_alloc
|
||||||
//
|
//
|
||||||
|
|
||||||
inline uint
|
inline uint
|
||||||
max_pvars()
|
total_pvars()
|
||||||
{
|
{
|
||||||
return m_psubsize + m_pvar.elements;
|
return m_total_pvars;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint
|
inline uint
|
||||||
|
@ -155,16 +163,15 @@ class sp_pcontext : public Sql_alloc
|
||||||
p->dflt= it;
|
p->dflt= it;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
sp_pvar_t *
|
||||||
push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
|
push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
|
||||||
|
|
||||||
// Pop the last 'num' slots of the frame
|
/*
|
||||||
inline void
|
Retrieve definitions of fields from the current context and its
|
||||||
pop_pvar(uint num = 1)
|
children.
|
||||||
{
|
*/
|
||||||
while (num--)
|
void
|
||||||
pop_dynamic(&m_pvar);
|
retrieve_field_definitions(List<create_field> *field_def_lst);
|
||||||
}
|
|
||||||
|
|
||||||
// Find by name
|
// Find by name
|
||||||
sp_pvar_t *
|
sp_pvar_t *
|
||||||
|
@ -175,7 +182,7 @@ class sp_pcontext : public Sql_alloc
|
||||||
find_pvar(uint offset);
|
find_pvar(uint offset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set the current scope boundary (for default values)
|
Set the current scope boundary (for default values).
|
||||||
The argument is the number of variables to skip.
|
The argument is the number of variables to skip.
|
||||||
*/
|
*/
|
||||||
inline void
|
inline void
|
||||||
|
@ -184,6 +191,45 @@ class sp_pcontext : public Sql_alloc
|
||||||
m_pboundary= n;
|
m_pboundary= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CASE expressions support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline int
|
||||||
|
register_case_expr()
|
||||||
|
{
|
||||||
|
return m_num_case_exprs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
get_num_case_exprs() const
|
||||||
|
{
|
||||||
|
return m_num_case_exprs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
push_case_expr_id(int case_expr_id)
|
||||||
|
{
|
||||||
|
return insert_dynamic(&m_case_expr_id_lst, (gptr) &case_expr_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
pop_case_expr_id()
|
||||||
|
{
|
||||||
|
pop_dynamic(&m_case_expr_id_lst);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
get_current_case_expr_id() const
|
||||||
|
{
|
||||||
|
int case_expr_id;
|
||||||
|
|
||||||
|
get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (gptr) &case_expr_id,
|
||||||
|
m_case_expr_id_lst.elements - 1);
|
||||||
|
|
||||||
|
return case_expr_id;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Labels
|
// Labels
|
||||||
//
|
//
|
||||||
|
@ -280,8 +326,18 @@ class sp_pcontext : public Sql_alloc
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
/*
|
||||||
|
m_total_pvars -- number of variables (including all types of arguments)
|
||||||
|
in this context including all children contexts.
|
||||||
|
|
||||||
|
m_total_pvars >= m_pvar.elements.
|
||||||
|
|
||||||
|
m_total_pvars of the root parsing context contains number of all
|
||||||
|
variables (including arguments) in all enclosed contexts.
|
||||||
|
*/
|
||||||
|
uint m_total_pvars;
|
||||||
|
|
||||||
// The maximum sub context's framesizes
|
// The maximum sub context's framesizes
|
||||||
uint m_psubsize;
|
|
||||||
uint m_csubsize;
|
uint m_csubsize;
|
||||||
uint m_hsubsize;
|
uint m_hsubsize;
|
||||||
uint m_handlers; // No. of handlers in this context
|
uint m_handlers; // No. of handlers in this context
|
||||||
|
@ -290,8 +346,19 @@ private:
|
||||||
|
|
||||||
sp_pcontext *m_parent; // Parent context
|
sp_pcontext *m_parent; // Parent context
|
||||||
|
|
||||||
uint m_poffset; // Variable offset for this context
|
/*
|
||||||
|
m_poffset -- basically, this is an index of the first variable in this
|
||||||
|
parsing context.
|
||||||
|
|
||||||
|
m_poffset is 0 for root context.
|
||||||
|
|
||||||
|
Since now each variable is stored in separate place, no reuse is done,
|
||||||
|
so m_poffset is different for all enclosed contexts.
|
||||||
|
*/
|
||||||
|
uint m_poffset;
|
||||||
|
|
||||||
uint m_coffset; // Cursor offset for this context
|
uint m_coffset; // Cursor offset for this context
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Boundary for finding variables in this context. This is the number
|
Boundary for finding variables in this context. This is the number
|
||||||
of variables currently "invisible" to default clauses.
|
of variables currently "invisible" to default clauses.
|
||||||
|
@ -300,7 +367,10 @@ private:
|
||||||
*/
|
*/
|
||||||
uint m_pboundary;
|
uint m_pboundary;
|
||||||
|
|
||||||
|
int m_num_case_exprs;
|
||||||
|
|
||||||
DYNAMIC_ARRAY m_pvar; // Parameters/variables
|
DYNAMIC_ARRAY m_pvar; // Parameters/variables
|
||||||
|
DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */
|
||||||
DYNAMIC_ARRAY m_cond; // Conditions
|
DYNAMIC_ARRAY m_cond; // Conditions
|
||||||
DYNAMIC_ARRAY m_cursor; // Cursors
|
DYNAMIC_ARRAY m_cursor; // Cursors
|
||||||
DYNAMIC_ARRAY m_handler; // Handlers, for checking of duplicates
|
DYNAMIC_ARRAY m_handler; // Handlers, for checking of duplicates
|
||||||
|
|
|
@ -29,41 +29,137 @@
|
||||||
#include "sp_rcontext.h"
|
#include "sp_rcontext.h"
|
||||||
#include "sp_pcontext.h"
|
#include "sp_pcontext.h"
|
||||||
|
|
||||||
sp_rcontext::sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax)
|
|
||||||
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
|
sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
|
||||||
m_ihsp(0), m_hfound(-1), m_ccount(0), m_prev_ctx(prev)
|
Field *return_value_fld,
|
||||||
|
sp_rcontext *prev_runtime_ctx)
|
||||||
|
:m_root_parsing_ctx(root_parsing_ctx),
|
||||||
|
m_var_table(0),
|
||||||
|
m_var_items(0),
|
||||||
|
m_return_value_fld(return_value_fld),
|
||||||
|
m_return_value_set(FALSE),
|
||||||
|
m_hcount(0),
|
||||||
|
m_hsp(0),
|
||||||
|
m_ihsp(0),
|
||||||
|
m_hfound(-1),
|
||||||
|
m_ccount(0),
|
||||||
|
m_case_expr_holders(0),
|
||||||
|
m_prev_runtime_ctx(prev_runtime_ctx)
|
||||||
{
|
{
|
||||||
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
|
|
||||||
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
|
|
||||||
m_hstack= (uint *)sql_alloc(hmax * sizeof(uint));
|
|
||||||
m_in_handler= (uint *)sql_alloc(hmax * sizeof(uint));
|
|
||||||
m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *));
|
|
||||||
m_saved.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
sp_rcontext::~sp_rcontext()
|
||||||
sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr,
|
|
||||||
enum_field_types type)
|
|
||||||
{
|
{
|
||||||
Item *it;
|
if (m_var_table)
|
||||||
Item *reuse_it;
|
free_blobs(m_var_table);
|
||||||
/* sp_eval_func_item will use callers_arena */
|
}
|
||||||
int res;
|
|
||||||
|
|
||||||
reuse_it= get_item(idx);
|
|
||||||
it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE);
|
/*
|
||||||
if (! it)
|
Initialize sp_rcontext instance.
|
||||||
res= -1;
|
|
||||||
else
|
SYNOPSIS
|
||||||
|
thd Thread handle
|
||||||
|
RETURN
|
||||||
|
FALSE on success
|
||||||
|
TRUE on error
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool sp_rcontext::init(THD *thd)
|
||||||
|
{
|
||||||
|
if (init_var_table(thd) || init_var_items())
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return
|
||||||
|
!(m_handler=
|
||||||
|
(sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handlers() *
|
||||||
|
sizeof(sp_handler_t))) ||
|
||||||
|
!(m_hstack=
|
||||||
|
(uint*)thd->alloc(m_root_parsing_ctx->max_handlers() *
|
||||||
|
sizeof(uint))) ||
|
||||||
|
!(m_in_handler=
|
||||||
|
(uint*)thd->alloc(m_root_parsing_ctx->max_handlers() *
|
||||||
|
sizeof(uint))) ||
|
||||||
|
!(m_cstack=
|
||||||
|
(sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursors() *
|
||||||
|
sizeof(sp_cursor*))) ||
|
||||||
|
!(m_case_expr_holders=
|
||||||
|
(Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() *
|
||||||
|
sizeof (Item_cache*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create and initialize a table to store SP-vars.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
thd Thread handler.
|
||||||
|
RETURN
|
||||||
|
FALSE on success
|
||||||
|
TRUE on error
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
sp_rcontext::init_var_table(THD *thd)
|
||||||
|
{
|
||||||
|
List<create_field> field_def_lst;
|
||||||
|
|
||||||
|
if (!m_root_parsing_ctx->total_pvars())
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
|
||||||
|
|
||||||
|
DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->total_pvars());
|
||||||
|
|
||||||
|
if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
m_var_table->copy_blobs= TRUE;
|
||||||
|
m_var_table->alias= "";
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create and initialize an Item-adapter (Item_field) for each SP-var field.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
FALSE on success
|
||||||
|
TRUE on error
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
sp_rcontext::init_var_items()
|
||||||
|
{
|
||||||
|
uint idx;
|
||||||
|
uint num_vars= m_root_parsing_ctx->total_pvars();
|
||||||
|
|
||||||
|
if (!(m_var_items= (Item**) sql_alloc(num_vars * sizeof (Item *))))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
for (idx = 0; idx < num_vars; ++idx)
|
||||||
{
|
{
|
||||||
res= 0;
|
if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx])))
|
||||||
set_item(idx, it);
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
sp_rcontext::set_return_value(THD *thd, Item *return_value_item)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(m_return_value_fld);
|
||||||
|
|
||||||
|
m_return_value_set = TRUE;
|
||||||
|
|
||||||
|
return sp_eval_expr(thd, m_return_value_fld, return_value_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sp_rcontext::find_handler(uint sql_errno,
|
sp_rcontext::find_handler(uint sql_errno,
|
||||||
MYSQL_ERROR::enum_warning_level level)
|
MYSQL_ERROR::enum_warning_level level)
|
||||||
|
@ -117,32 +213,14 @@ sp_rcontext::find_handler(uint sql_errno,
|
||||||
}
|
}
|
||||||
if (found < 0)
|
if (found < 0)
|
||||||
{
|
{
|
||||||
if (m_prev_ctx)
|
if (m_prev_runtime_ctx)
|
||||||
return m_prev_ctx->find_handler(sql_errno, level);
|
return m_prev_runtime_ctx->find_handler(sql_errno, level);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
m_hfound= found;
|
m_hfound= found;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
sp_rcontext::save_variables(uint fp)
|
|
||||||
{
|
|
||||||
while (fp < m_count)
|
|
||||||
{
|
|
||||||
m_saved.push_front(m_frame[fp]);
|
|
||||||
m_frame[fp++]= NULL; // Prevent reuse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sp_rcontext::restore_variables(uint fp)
|
|
||||||
{
|
|
||||||
uint i= m_count;
|
|
||||||
|
|
||||||
while (i-- > fp)
|
|
||||||
m_frame[i]= m_saved.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
||||||
|
@ -150,6 +228,7 @@ sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
||||||
m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i);
|
m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sp_rcontext::pop_cursors(uint count)
|
sp_rcontext::pop_cursors(uint count)
|
||||||
{
|
{
|
||||||
|
@ -160,6 +239,40 @@ sp_rcontext::pop_cursors(uint count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_rcontext::set_variable(THD *thd, uint var_idx, Item *value)
|
||||||
|
{
|
||||||
|
return set_variable(thd, m_var_table->field[var_idx], value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_rcontext::set_variable(THD *thd, Field *field, Item *value)
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
field->set_null();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sp_eval_expr(thd, field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item *
|
||||||
|
sp_rcontext::get_item(uint var_idx)
|
||||||
|
{
|
||||||
|
return m_var_items[var_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item **
|
||||||
|
sp_rcontext::get_item_addr(uint var_idx)
|
||||||
|
{
|
||||||
|
return m_var_items + var_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* sp_cursor
|
* sp_cursor
|
||||||
|
@ -263,6 +376,102 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create an instance of appropriate Item_cache class depending on the
|
||||||
|
specified type in the callers arena.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
thd thread handler
|
||||||
|
result_type type of the expression
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
Pointer to valid object on success
|
||||||
|
NULL on error
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
We should create cache items in the callers arena, as they are used
|
||||||
|
between in several instructions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Item_cache *
|
||||||
|
sp_rcontext::create_case_expr_holder(THD *thd, Item_result result_type)
|
||||||
|
{
|
||||||
|
Item_cache *holder;
|
||||||
|
Query_arena current_arena;
|
||||||
|
|
||||||
|
thd->set_n_backup_active_arena(thd->spcont->callers_arena, ¤t_arena);
|
||||||
|
|
||||||
|
holder= Item_cache::get_cache(result_type);
|
||||||
|
|
||||||
|
thd->restore_active_arena(thd->spcont->callers_arena, ¤t_arena);
|
||||||
|
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set CASE expression to the specified value.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
thd thread handler
|
||||||
|
case_expr_id identifier of the CASE expression
|
||||||
|
case_expr_item a value of the CASE expression
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
FALSE on success
|
||||||
|
TRUE on error
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
The idea is to reuse Item_cache for the expression of the one CASE
|
||||||
|
statement. This optimization takes place when there is CASE statement
|
||||||
|
inside of a loop. So, in other words, we will use the same object on each
|
||||||
|
iteration instead of creating a new one for each iteration.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
Hypothetically, a type of CASE expression can be different for each
|
||||||
|
iteration. For instance, this can happen if the expression contains a
|
||||||
|
session variable (something like @@VAR) and its type is changed from one
|
||||||
|
iteration to another.
|
||||||
|
|
||||||
|
In order to cope with this problem, we check type each time, when we use
|
||||||
|
already created object. If the type does not match, we re-create Item.
|
||||||
|
This also can (should?) be optimized.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item)
|
||||||
|
{
|
||||||
|
if (!(case_expr_item= sp_prepare_func_item(thd, &case_expr_item)))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!m_case_expr_holders[case_expr_id] ||
|
||||||
|
m_case_expr_holders[case_expr_id]->result_type() !=
|
||||||
|
case_expr_item->result_type())
|
||||||
|
{
|
||||||
|
m_case_expr_holders[case_expr_id]=
|
||||||
|
create_case_expr_holder(thd, case_expr_item->result_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_case_expr_holders[case_expr_id]->store(case_expr_item);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item *
|
||||||
|
sp_rcontext::get_case_expr(int case_expr_id)
|
||||||
|
{
|
||||||
|
return m_case_expr_holders[case_expr_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item **
|
||||||
|
sp_rcontext::get_case_expr_addr(int case_expr_id)
|
||||||
|
{
|
||||||
|
return (Item**) m_case_expr_holders + case_expr_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
Select_fetch_into_spvars
|
Select_fetch_into_spvars
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -294,11 +503,8 @@ bool Select_fetch_into_spvars::send_data(List<Item> &items)
|
||||||
*/
|
*/
|
||||||
for (; pv= pv_iter++, item= item_iter++; )
|
for (; pv= pv_iter++, item= item_iter++; )
|
||||||
{
|
{
|
||||||
Item *reuse= thd->spcont->get_item(pv->offset);
|
if (thd->spcont->set_variable(thd, pv->offset, item))
|
||||||
/* Evaluate a new item on the arena of the calling instruction */
|
return TRUE;
|
||||||
Item *it= sp_eval_func_item(thd, &item, pv->type, reuse, TRUE);
|
|
||||||
|
|
||||||
thd->spcont->set_item(pv->offset, it);
|
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,12 +43,22 @@ typedef struct
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is a run context? of one SP ?
|
This class is a runtime context of a Stored Routine. It is used in an
|
||||||
THis is
|
execution and is intended to contain all dynamic objects (i.e. objects, which
|
||||||
- a stack of cursors?
|
can be changed during execution), such as:
|
||||||
- a stack of handlers?
|
- stored routine variables;
|
||||||
- a stack of Items ?
|
- cursors;
|
||||||
- a stack of instruction locations in SP?
|
- handlers;
|
||||||
|
|
||||||
|
Runtime context is used with sp_head class. sp_head class is intended to
|
||||||
|
contain all static things, related to the stored routines (code, for example).
|
||||||
|
sp_head instance creates runtime context for the execution of a stored
|
||||||
|
routine.
|
||||||
|
|
||||||
|
There is a parsing context (an instance of sp_pcontext class), which is used
|
||||||
|
on parsing stage. However, now it contains some necessary for an execution
|
||||||
|
things, such as definition of used stored routine variables. That's why
|
||||||
|
runtime context needs a reference to the parsing context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class sp_rcontext : public Sql_alloc
|
class sp_rcontext : public Sql_alloc
|
||||||
|
@ -68,62 +78,34 @@ class sp_rcontext : public Sql_alloc
|
||||||
|
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
/*
|
/*
|
||||||
Routine to which this Item_splocal belongs. Used for checking if correct
|
The routine for which this runtime context is created. Used for checking
|
||||||
runtime context is used for variable handling.
|
if correct runtime context is used for variable handling.
|
||||||
*/
|
*/
|
||||||
sp_head *owner;
|
sp_head *sp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sp_rcontext(sp_rcontext *prev, uint fsize, uint hmax, uint cmax);
|
sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld,
|
||||||
|
sp_rcontext *prev_runtime_ctx);
|
||||||
|
bool init(THD *thd);
|
||||||
|
|
||||||
~sp_rcontext()
|
~sp_rcontext();
|
||||||
{
|
|
||||||
// Not needed?
|
|
||||||
//sql_element_free(m_frame);
|
|
||||||
//m_saved.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
push_item(Item *i)
|
|
||||||
{
|
|
||||||
if (m_count < m_fsize)
|
|
||||||
m_frame[m_count++]= i;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
set_item(uint idx, Item *i)
|
|
||||||
{
|
|
||||||
if (idx < m_count)
|
|
||||||
m_frame[idx]= i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns 0 on success, -1 on (eval) failure */
|
|
||||||
int
|
int
|
||||||
set_item_eval(THD *thd, uint idx, Item **i, enum_field_types type);
|
set_variable(THD *thd, uint var_idx, Item *value);
|
||||||
|
|
||||||
inline Item *
|
Item *
|
||||||
get_item(uint idx)
|
get_item(uint var_idx);
|
||||||
|
|
||||||
|
Item **
|
||||||
|
get_item_addr(uint var_idx);
|
||||||
|
|
||||||
|
bool
|
||||||
|
set_return_value(THD *thd, Item *return_value_item);
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
is_return_value_set() const
|
||||||
{
|
{
|
||||||
return m_frame[idx];
|
return m_return_value_set;
|
||||||
}
|
|
||||||
|
|
||||||
inline Item **
|
|
||||||
get_item_addr(uint idx)
|
|
||||||
{
|
|
||||||
return m_frame + idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
|
||||||
set_result(Item *it)
|
|
||||||
{
|
|
||||||
m_result= it;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Item *
|
|
||||||
get_result()
|
|
||||||
{
|
|
||||||
return m_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -195,14 +177,6 @@ class sp_rcontext : public Sql_alloc
|
||||||
m_ihsp-= 1;
|
m_ihsp-= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save variables starting at fp and up
|
|
||||||
void
|
|
||||||
save_variables(uint fp);
|
|
||||||
|
|
||||||
// Restore variables down to fp
|
|
||||||
void
|
|
||||||
restore_variables(uint fp);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
|
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
|
||||||
|
|
||||||
|
@ -221,13 +195,42 @@ class sp_rcontext : public Sql_alloc
|
||||||
return m_cstack[i];
|
return m_cstack[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CASE expressions support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item);
|
||||||
|
|
||||||
|
Item *
|
||||||
|
get_case_expr(int case_expr_id);
|
||||||
|
|
||||||
|
Item **
|
||||||
|
get_case_expr_addr(int case_expr_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
sp_pcontext *m_root_parsing_ctx;
|
||||||
|
|
||||||
uint m_count;
|
/* Virtual table for storing variables. */
|
||||||
uint m_fsize;
|
TABLE *m_var_table;
|
||||||
Item **m_frame;
|
|
||||||
|
|
||||||
Item *m_result; // For FUNCTIONs
|
/*
|
||||||
|
Collection of Item_field proxies, each of them points to the corresponding
|
||||||
|
field in m_var_table.
|
||||||
|
*/
|
||||||
|
Item **m_var_items;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a pointer to a field, which should contain return value for stored
|
||||||
|
functions (only). For stored procedures, this pointer is NULL.
|
||||||
|
*/
|
||||||
|
Field *m_return_value_fld;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Indicates whether the return value (in m_return_value_fld) has been set
|
||||||
|
during execution.
|
||||||
|
*/
|
||||||
|
bool m_return_value_set;
|
||||||
|
|
||||||
sp_handler_t *m_handler; // Visible handlers
|
sp_handler_t *m_handler; // Visible handlers
|
||||||
uint m_hcount; // Stack pointer for m_handler
|
uint m_hcount; // Stack pointer for m_handler
|
||||||
|
@ -236,13 +239,22 @@ private:
|
||||||
uint *m_in_handler; // Active handler, for recursion check
|
uint *m_in_handler; // Active handler, for recursion check
|
||||||
uint m_ihsp; // Stack pointer for m_in_handler
|
uint m_ihsp; // Stack pointer for m_in_handler
|
||||||
int m_hfound; // Set by find_handler; -1 if not found
|
int m_hfound; // Set by find_handler; -1 if not found
|
||||||
List<Item> m_saved; // Saved variables during handler exec.
|
|
||||||
|
|
||||||
sp_cursor **m_cstack;
|
sp_cursor **m_cstack;
|
||||||
uint m_ccount;
|
uint m_ccount;
|
||||||
|
|
||||||
sp_rcontext *m_prev_ctx; // Previous context (NULL if none)
|
Item_cache **m_case_expr_holders;
|
||||||
|
|
||||||
|
/* Previous runtime context (NULL if none) */
|
||||||
|
sp_rcontext *m_prev_runtime_ctx;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool init_var_table(THD *thd);
|
||||||
|
bool init_var_items();
|
||||||
|
|
||||||
|
Item_cache *create_case_expr_holder(THD *thd, Item_result result_type);
|
||||||
|
|
||||||
|
int set_variable(THD *thd, Field *field, Item *value);
|
||||||
}; // class sp_rcontext : public Sql_alloc
|
}; // class sp_rcontext : public Sql_alloc
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1503,10 +1503,10 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
||||||
my_var *mv= gl++;
|
my_var *mv= gl++;
|
||||||
if (mv->local)
|
if (mv->local)
|
||||||
{
|
{
|
||||||
Item_splocal *var;
|
Item_splocal *var= new Item_splocal(mv->s, mv->offset, mv->type);
|
||||||
(void)local_vars.push_back(var= new Item_splocal(mv->s, mv->offset));
|
(void)local_vars.push_back(var);
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
var->owner= mv->owner;
|
var->m_sp= mv->sp;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1779,8 +1779,8 @@ bool select_dumpvar::send_data(List<Item> &items)
|
||||||
{
|
{
|
||||||
if ((yy=var_li++))
|
if ((yy=var_li++))
|
||||||
{
|
{
|
||||||
if (thd->spcont->set_item_eval(current_thd,
|
if (thd->spcont->set_variable(current_thd, yy->get_var_idx(),
|
||||||
yy->get_offset(), it.ref(), zz->type))
|
*it.ref()))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2100,7 +2100,7 @@ public:
|
||||||
Routine to which this Item_splocal belongs. Used for checking if correct
|
Routine to which this Item_splocal belongs. Used for checking if correct
|
||||||
runtime context is used for variable handling.
|
runtime context is used for variable handling.
|
||||||
*/
|
*/
|
||||||
sp_head *owner;
|
sp_head *sp;
|
||||||
#endif
|
#endif
|
||||||
bool local;
|
bool local;
|
||||||
uint offset;
|
uint offset;
|
||||||
|
|
328
sql/sql_parse.cc
328
sql/sql_parse.cc
|
@ -5770,9 +5770,10 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
||||||
buf, "TIMESTAMP");
|
buf, "TIMESTAMP");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
|
if (!(new_field= new create_field()) ||
|
||||||
type_modifier, default_value, on_update_value,
|
new_field->init(thd, field_name, type, length, decimals, type_modifier,
|
||||||
comment, change, interval_list, cs, uint_geom_type)))
|
default_value, on_update_value, comment, change,
|
||||||
|
interval_list, cs, uint_geom_type))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
lex->create_list.push_back(new_field);
|
lex->create_list.push_back(new_field);
|
||||||
|
@ -5780,327 +5781,6 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
** Create field definition for create
|
|
||||||
** Return 0 on failure, otherwise return create_field instance
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
create_field *
|
|
||||||
new_create_field(THD *thd, char *field_name, enum_field_types type,
|
|
||||||
char *length, char *decimals,
|
|
||||||
uint type_modifier,
|
|
||||||
Item *default_value, Item *on_update_value,
|
|
||||||
LEX_STRING *comment,
|
|
||||||
char *change, List<String> *interval_list, CHARSET_INFO *cs,
|
|
||||||
uint uint_geom_type)
|
|
||||||
{
|
|
||||||
register create_field *new_field;
|
|
||||||
uint sign_len, allowed_type_modifier=0;
|
|
||||||
ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
|
|
||||||
DBUG_ENTER("new_create_field");
|
|
||||||
|
|
||||||
if (!(new_field=new create_field()))
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
new_field->field=0;
|
|
||||||
new_field->field_name=field_name;
|
|
||||||
new_field->def= default_value;
|
|
||||||
new_field->flags= type_modifier;
|
|
||||||
new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
|
|
||||||
Field::NEXT_NUMBER : Field::NONE);
|
|
||||||
new_field->decimals= decimals ? (uint)atoi(decimals) : 0;
|
|
||||||
if (new_field->decimals >= NOT_FIXED_DEC)
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_BIG_SCALE, MYF(0), new_field->decimals, field_name,
|
|
||||||
NOT_FIXED_DEC-1);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_field->sql_type=type;
|
|
||||||
new_field->length=0;
|
|
||||||
new_field->change=change;
|
|
||||||
new_field->interval=0;
|
|
||||||
new_field->pack_length= new_field->key_length= 0;
|
|
||||||
new_field->charset=cs;
|
|
||||||
new_field->geom_type= (Field::geometry_type) uint_geom_type;
|
|
||||||
|
|
||||||
new_field->comment=*comment;
|
|
||||||
/*
|
|
||||||
Set flag if this field doesn't have a default value
|
|
||||||
*/
|
|
||||||
if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
|
|
||||||
(type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP)
|
|
||||||
new_field->flags|= NO_DEFAULT_VALUE_FLAG;
|
|
||||||
|
|
||||||
if (length && !(new_field->length= (uint) atoi(length)))
|
|
||||||
length=0; /* purecov: inspected */
|
|
||||||
sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case FIELD_TYPE_TINY:
|
|
||||||
if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
|
|
||||||
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_SHORT:
|
|
||||||
if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
|
|
||||||
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_INT24:
|
|
||||||
if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
|
|
||||||
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_LONG:
|
|
||||||
if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
|
|
||||||
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_LONGLONG:
|
|
||||||
if (!length) new_field->length=MAX_BIGINT_WIDTH;
|
|
||||||
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_NULL:
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_NEWDECIMAL:
|
|
||||||
if (!length && !new_field->decimals)
|
|
||||||
new_field->length= 10;
|
|
||||||
if (new_field->length > DECIMAL_MAX_PRECISION)
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_BIG_PRECISION, MYF(0), new_field->length, field_name,
|
|
||||||
DECIMAL_MAX_PRECISION);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
if (new_field->length < new_field->decimals)
|
|
||||||
{
|
|
||||||
my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
new_field->length=
|
|
||||||
my_decimal_precision_to_length(new_field->length, new_field->decimals,
|
|
||||||
type_modifier & UNSIGNED_FLAG);
|
|
||||||
new_field->pack_length=
|
|
||||||
my_decimal_get_binary_size(new_field->length, new_field->decimals);
|
|
||||||
break;
|
|
||||||
case MYSQL_TYPE_VARCHAR:
|
|
||||||
/*
|
|
||||||
Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
|
|
||||||
if they don't have a default value
|
|
||||||
*/
|
|
||||||
max_field_charlength= MAX_FIELD_VARCHARLENGTH;
|
|
||||||
break;
|
|
||||||
case MYSQL_TYPE_STRING:
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_BLOB:
|
|
||||||
case FIELD_TYPE_TINY_BLOB:
|
|
||||||
case FIELD_TYPE_LONG_BLOB:
|
|
||||||
case FIELD_TYPE_MEDIUM_BLOB:
|
|
||||||
case FIELD_TYPE_GEOMETRY:
|
|
||||||
if (default_value) // Allow empty as default value
|
|
||||||
{
|
|
||||||
String str,*res;
|
|
||||||
res=default_value->val_str(&str);
|
|
||||||
if (res->length())
|
|
||||||
{
|
|
||||||
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
|
|
||||||
field_name); /* purecov: inspected */
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
new_field->def=0;
|
|
||||||
}
|
|
||||||
new_field->flags|=BLOB_FLAG;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_YEAR:
|
|
||||||
if (!length || new_field->length != 2)
|
|
||||||
new_field->length=4; // Default length
|
|
||||||
new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_FLOAT:
|
|
||||||
/* change FLOAT(precision) to FLOAT or DOUBLE */
|
|
||||||
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
|
||||||
if (length && !decimals)
|
|
||||||
{
|
|
||||||
uint tmp_length=new_field->length;
|
|
||||||
if (tmp_length > PRECISION_FOR_DOUBLE)
|
|
||||||
{
|
|
||||||
my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
else if (tmp_length > PRECISION_FOR_FLOAT)
|
|
||||||
{
|
|
||||||
new_field->sql_type=FIELD_TYPE_DOUBLE;
|
|
||||||
new_field->length=DBL_DIG+7; // -[digits].E+###
|
|
||||||
}
|
|
||||||
else
|
|
||||||
new_field->length=FLT_DIG+6; // -[digits].E+##
|
|
||||||
new_field->decimals= NOT_FIXED_DEC;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!length && !decimals)
|
|
||||||
{
|
|
||||||
new_field->length = FLT_DIG+6;
|
|
||||||
new_field->decimals= NOT_FIXED_DEC;
|
|
||||||
}
|
|
||||||
if (new_field->length < new_field->decimals &&
|
|
||||||
new_field->decimals != NOT_FIXED_DEC)
|
|
||||||
{
|
|
||||||
my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_DOUBLE:
|
|
||||||
allowed_type_modifier= AUTO_INCREMENT_FLAG;
|
|
||||||
if (!length && !decimals)
|
|
||||||
{
|
|
||||||
new_field->length = DBL_DIG+7;
|
|
||||||
new_field->decimals=NOT_FIXED_DEC;
|
|
||||||
}
|
|
||||||
if (new_field->length < new_field->decimals &&
|
|
||||||
new_field->decimals != NOT_FIXED_DEC)
|
|
||||||
{
|
|
||||||
my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_TIMESTAMP:
|
|
||||||
if (!length)
|
|
||||||
new_field->length= 14; // Full date YYYYMMDDHHMMSS
|
|
||||||
else if (new_field->length != 19)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
We support only even TIMESTAMP lengths less or equal than 14
|
|
||||||
and 19 as length of 4.1 compatible representation.
|
|
||||||
*/
|
|
||||||
new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
|
|
||||||
new_field->length= min(new_field->length,14); /* purecov: inspected */
|
|
||||||
}
|
|
||||||
new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
|
|
||||||
if (default_value)
|
|
||||||
{
|
|
||||||
/* Grammar allows only NOW() value for ON UPDATE clause */
|
|
||||||
if (default_value->type() == Item::FUNC_ITEM &&
|
|
||||||
((Item_func*)default_value)->functype() == Item_func::NOW_FUNC)
|
|
||||||
{
|
|
||||||
new_field->unireg_check= (on_update_value?Field::TIMESTAMP_DNUN_FIELD:
|
|
||||||
Field::TIMESTAMP_DN_FIELD);
|
|
||||||
/*
|
|
||||||
We don't need default value any longer moreover it is dangerous.
|
|
||||||
Everything handled by unireg_check further.
|
|
||||||
*/
|
|
||||||
new_field->def= 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
new_field->unireg_check= (on_update_value?Field::TIMESTAMP_UN_FIELD:
|
|
||||||
Field::NONE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
|
|
||||||
or ON UPDATE values then for the sake of compatiblity we should treat
|
|
||||||
this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
|
|
||||||
have another TIMESTAMP column with auto-set option before this one)
|
|
||||||
or DEFAULT 0 (in other cases).
|
|
||||||
So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
|
|
||||||
replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
|
|
||||||
information about all TIMESTAMP fields in table will be availiable.
|
|
||||||
|
|
||||||
If we have TIMESTAMP NULL column without explicit DEFAULT value
|
|
||||||
we treat it as having DEFAULT NULL attribute.
|
|
||||||
*/
|
|
||||||
new_field->unireg_check= (on_update_value ?
|
|
||||||
Field::TIMESTAMP_UN_FIELD :
|
|
||||||
(new_field->flags & NOT_NULL_FLAG ?
|
|
||||||
Field::TIMESTAMP_OLD_FIELD:
|
|
||||||
Field::NONE));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_DATE: // Old date type
|
|
||||||
if (protocol_version != PROTOCOL_VERSION-1)
|
|
||||||
new_field->sql_type=FIELD_TYPE_NEWDATE;
|
|
||||||
/* fall trough */
|
|
||||||
case FIELD_TYPE_NEWDATE:
|
|
||||||
new_field->length=10;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_TIME:
|
|
||||||
new_field->length=10;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_DATETIME:
|
|
||||||
new_field->length=19;
|
|
||||||
break;
|
|
||||||
case FIELD_TYPE_SET:
|
|
||||||
{
|
|
||||||
if (interval_list->elements > sizeof(longlong)*8)
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
new_field->pack_length= get_set_pack_length(interval_list->elements);
|
|
||||||
|
|
||||||
List_iterator<String> it(*interval_list);
|
|
||||||
String *tmp;
|
|
||||||
while ((tmp= it++))
|
|
||||||
new_field->interval_list.push_back(tmp);
|
|
||||||
/*
|
|
||||||
Set fake length to 1 to pass the below conditions.
|
|
||||||
Real length will be set in mysql_prepare_table()
|
|
||||||
when we know the character set of the column
|
|
||||||
*/
|
|
||||||
new_field->length= 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FIELD_TYPE_ENUM:
|
|
||||||
{
|
|
||||||
// Should be safe
|
|
||||||
new_field->pack_length= get_enum_pack_length(interval_list->elements);
|
|
||||||
|
|
||||||
List_iterator<String> it(*interval_list);
|
|
||||||
String *tmp;
|
|
||||||
while ((tmp= it++))
|
|
||||||
new_field->interval_list.push_back(tmp);
|
|
||||||
new_field->length= 1; // See comment for FIELD_TYPE_SET above.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MYSQL_TYPE_VAR_STRING:
|
|
||||||
DBUG_ASSERT(0); // Impossible
|
|
||||||
break;
|
|
||||||
case MYSQL_TYPE_BIT:
|
|
||||||
{
|
|
||||||
if (!length)
|
|
||||||
new_field->length= 1;
|
|
||||||
if (new_field->length > MAX_BIT_FIELD_LENGTH)
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name,
|
|
||||||
MAX_BIT_FIELD_LENGTH);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
new_field->pack_length= (new_field->length + 7) / 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FIELD_TYPE_DECIMAL:
|
|
||||||
DBUG_ASSERT(0); /* Was obsolete */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(new_field->flags & BLOB_FLAG) &&
|
|
||||||
((new_field->length > max_field_charlength && type != FIELD_TYPE_SET &&
|
|
||||||
type != FIELD_TYPE_ENUM &&
|
|
||||||
(type != MYSQL_TYPE_VARCHAR || default_value)) ||
|
|
||||||
(!new_field->length &&
|
|
||||||
type != MYSQL_TYPE_STRING &&
|
|
||||||
type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
|
|
||||||
{
|
|
||||||
my_error((type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_VARCHAR ||
|
|
||||||
type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH :
|
|
||||||
ER_TOO_BIG_DISPLAYWIDTH,
|
|
||||||
MYF(0),
|
|
||||||
field_name, max_field_charlength); /* purecov: inspected */
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
type_modifier&= AUTO_INCREMENT_FLAG;
|
|
||||||
if ((~allowed_type_modifier) & type_modifier)
|
|
||||||
{
|
|
||||||
my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(new_field);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Store position for column in ALTER TABLE .. ADD column */
|
/* Store position for column in ALTER TABLE .. ADD column */
|
||||||
|
|
||||||
|
|
|
@ -8911,6 +8911,7 @@ err:
|
||||||
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
|
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
|
||||||
{
|
{
|
||||||
uint field_count= field_list.elements;
|
uint field_count= field_list.elements;
|
||||||
|
uint blob_count= 0;
|
||||||
Field **field;
|
Field **field;
|
||||||
create_field *cdef; /* column definition */
|
create_field *cdef; /* column definition */
|
||||||
uint record_length= 0;
|
uint record_length= 0;
|
||||||
|
@ -8927,6 +8928,12 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
|
||||||
table->s= s= &table->share_not_to_be_used;
|
table->s= s= &table->share_not_to_be_used;
|
||||||
s->fields= field_count;
|
s->fields= field_count;
|
||||||
|
|
||||||
|
if (!(s->blob_field= (uint*)thd->alloc((field_list.elements + 1) *
|
||||||
|
sizeof(uint))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
s->blob_ptr_size= mi_portable_sizeof_char_ptr;
|
||||||
|
|
||||||
/* Create all fields and calculate the total length of record */
|
/* Create all fields and calculate the total length of record */
|
||||||
List_iterator_fast<create_field> it(field_list);
|
List_iterator_fast<create_field> it(field_list);
|
||||||
while ((cdef= it++))
|
while ((cdef= it++))
|
||||||
|
@ -8942,9 +8949,15 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
|
||||||
record_length+= (**field).pack_length();
|
record_length+= (**field).pack_length();
|
||||||
if (! ((**field).flags & NOT_NULL_FLAG))
|
if (! ((**field).flags & NOT_NULL_FLAG))
|
||||||
++null_count;
|
++null_count;
|
||||||
|
|
||||||
|
if ((*field)->flags & BLOB_FLAG)
|
||||||
|
s->blob_field[blob_count++]= (uint) (field - table->field);
|
||||||
|
|
||||||
++field;
|
++field;
|
||||||
}
|
}
|
||||||
*field= NULL; /* mark the end of the list */
|
*field= NULL; /* mark the end of the list */
|
||||||
|
s->blob_field[blob_count]= 0; /* mark the end of the list */
|
||||||
|
s->blob_fields= blob_count;
|
||||||
|
|
||||||
null_pack_length= (null_count + 7)/8;
|
null_pack_length= (null_count + 7)/8;
|
||||||
s->reclength= record_length + null_pack_length;
|
s->reclength= record_length + null_pack_length;
|
||||||
|
|
|
@ -406,7 +406,6 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||||
ORDER *group, bool distinct, bool save_sum_fields,
|
ORDER *group, bool distinct, bool save_sum_fields,
|
||||||
ulonglong select_options, ha_rows rows_limit,
|
ulonglong select_options, ha_rows rows_limit,
|
||||||
char* alias);
|
char* alias);
|
||||||
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
|
|
||||||
void free_tmp_table(THD *thd, TABLE *entry);
|
void free_tmp_table(THD *thd, TABLE *entry);
|
||||||
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
|
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
|
||||||
bool reset_with_sum_func);
|
bool reset_with_sum_func);
|
||||||
|
|
|
@ -1123,7 +1123,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||||
trg_action_time_type time_type,
|
trg_action_time_type time_type,
|
||||||
bool old_row_is_record1)
|
bool old_row_is_record1)
|
||||||
{
|
{
|
||||||
int res= 0;
|
bool err_status= FALSE;
|
||||||
sp_head *sp_trigger= bodies[event][time_type];
|
sp_head *sp_trigger= bodies[event][time_type];
|
||||||
|
|
||||||
if (sp_trigger)
|
if (sp_trigger)
|
||||||
|
@ -1183,7 +1183,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||||
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
|
||||||
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
|
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
|
||||||
res= sp_trigger->execute_function(thd, 0, 0, 0);
|
err_status= sp_trigger->execute_function(thd, 0, 0, 0);
|
||||||
thd->restore_sub_statement_state(&statement_state);
|
thd->restore_sub_statement_state(&statement_state);
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
@ -1191,7 +1191,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||||
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return err_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
227
sql/sql_yacc.yy
227
sql/sql_yacc.yy
|
@ -1350,41 +1350,11 @@ create_function_tail:
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_head *sp= lex->sphead;
|
sp_head *sp= lex->sphead;
|
||||||
LEX_STRING cmt = { 0, 0 };
|
|
||||||
create_field *new_field;
|
|
||||||
uint unused1= 0;
|
|
||||||
int unused2= 0;
|
|
||||||
|
|
||||||
if (!(new_field= new_create_field(YYTHD, (char*) "",
|
if (sp->fill_field_definition(YYTHD, lex,
|
||||||
(enum enum_field_types)$8,
|
(enum enum_field_types) $8,
|
||||||
lex->length, lex->dec, lex->type,
|
&sp->m_return_field_def))
|
||||||
(Item *)0, (Item *) 0, &cmt, 0,
|
YYABORT;
|
||||||
&lex->interval_list,
|
|
||||||
(lex->charset ? lex->charset :
|
|
||||||
default_charset_info),
|
|
||||||
lex->uint_geom_type)))
|
|
||||||
YYABORT;
|
|
||||||
|
|
||||||
sp->m_returns_cs= new_field->charset;
|
|
||||||
|
|
||||||
if (new_field->interval_list.elements)
|
|
||||||
{
|
|
||||||
new_field->interval=
|
|
||||||
sp->create_typelib(&new_field->interval_list);
|
|
||||||
}
|
|
||||||
sp_prepare_create_field(YYTHD, new_field);
|
|
||||||
|
|
||||||
if (prepare_create_field(new_field, &unused1, &unused2, &unused2,
|
|
||||||
HA_CAN_GEOMETRY))
|
|
||||||
YYABORT;
|
|
||||||
|
|
||||||
sp->m_returns= new_field->sql_type;
|
|
||||||
sp->m_returns_cs= new_field->charset;
|
|
||||||
sp->m_returns_len= new_field->length;
|
|
||||||
sp->m_returns_pack= new_field->pack_flag;
|
|
||||||
sp->m_returns_typelib= new_field->interval;
|
|
||||||
sp->m_geom_returns= new_field->geom_type;
|
|
||||||
new_field->interval= NULL;
|
|
||||||
|
|
||||||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||||||
}
|
}
|
||||||
|
@ -1506,8 +1476,28 @@ sp_fdparams:
|
||||||
| sp_fdparam
|
| sp_fdparam
|
||||||
;
|
;
|
||||||
|
|
||||||
|
sp_init_param:
|
||||||
|
/* Empty */
|
||||||
|
{
|
||||||
|
LEX *lex= Lex;
|
||||||
|
|
||||||
|
lex->length= 0;
|
||||||
|
lex->dec= 0;
|
||||||
|
lex->type= 0;
|
||||||
|
|
||||||
|
lex->default_value= 0;
|
||||||
|
lex->on_update_value= 0;
|
||||||
|
|
||||||
|
lex->comment= null_lex_str;
|
||||||
|
lex->charset= NULL;
|
||||||
|
|
||||||
|
lex->interval_list.empty();
|
||||||
|
lex->uint_geom_type= 0;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
sp_fdparam:
|
sp_fdparam:
|
||||||
ident type
|
ident sp_init_param type
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_pcontext *spc= lex->spcont;
|
sp_pcontext *spc= lex->spcont;
|
||||||
|
@ -1517,7 +1507,17 @@ sp_fdparam:
|
||||||
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
|
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
spc->push_pvar(&$1, (enum enum_field_types)$2, sp_param_in);
|
sp_pvar_t *pvar= spc->push_pvar(&$1, (enum enum_field_types)$3,
|
||||||
|
sp_param_in);
|
||||||
|
|
||||||
|
if (lex->sphead->fill_field_definition(YYTHD, lex,
|
||||||
|
(enum enum_field_types) $3,
|
||||||
|
&pvar->field_def))
|
||||||
|
{
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
pvar->field_def.field_name= pvar->name.str;
|
||||||
|
pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1533,18 +1533,27 @@ sp_pdparams:
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_pdparam:
|
sp_pdparam:
|
||||||
sp_opt_inout ident type
|
sp_opt_inout sp_init_param ident type
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_pcontext *spc= lex->spcont;
|
sp_pcontext *spc= lex->spcont;
|
||||||
|
|
||||||
if (spc->find_pvar(&$2, TRUE))
|
if (spc->find_pvar(&$3, TRUE))
|
||||||
{
|
{
|
||||||
my_error(ER_SP_DUP_PARAM, MYF(0), $2.str);
|
my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
spc->push_pvar(&$2, (enum enum_field_types)$3,
|
sp_pvar_t *pvar= spc->push_pvar(&$3, (enum enum_field_types)$4,
|
||||||
(sp_param_mode_t)$1);
|
(sp_param_mode_t)$1);
|
||||||
|
|
||||||
|
if (lex->sphead->fill_field_definition(YYTHD, lex,
|
||||||
|
(enum enum_field_types) $4,
|
||||||
|
&pvar->field_def))
|
||||||
|
{
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
pvar->field_def.field_name= pvar->name.str;
|
||||||
|
pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1596,45 +1605,60 @@ sp_decls:
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_decl:
|
sp_decl:
|
||||||
DECLARE_SYM sp_decl_idents type
|
DECLARE_SYM sp_decl_idents
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
|
|
||||||
lex->sphead->reset_lex(YYTHD);
|
lex->sphead->reset_lex(YYTHD);
|
||||||
lex->spcont->declare_var_boundary($2);
|
lex->spcont->declare_var_boundary($2);
|
||||||
}
|
}
|
||||||
|
type
|
||||||
sp_opt_default
|
sp_opt_default
|
||||||
{
|
{
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_pcontext *ctx= lex->spcont;
|
sp_pcontext *pctx= lex->spcont;
|
||||||
uint max= ctx->context_pvars();
|
uint num_vars= pctx->context_pvars();
|
||||||
enum enum_field_types type= (enum enum_field_types)$3;
|
enum enum_field_types var_type= (enum enum_field_types) $4;
|
||||||
Item *it= $5;
|
Item *dflt_value_item= $5;
|
||||||
bool has_default= (it != NULL);
|
create_field *create_field_op;
|
||||||
|
|
||||||
for (uint i = max-$2 ; i < max ; i++)
|
if (!dflt_value_item)
|
||||||
{
|
{
|
||||||
sp_instr_set *in;
|
dflt_value_item= new Item_null();
|
||||||
uint off= ctx->pvar_context2index(i);
|
/* QQ Set to the var_type with null_value? */
|
||||||
|
|
||||||
ctx->set_type(off, type);
|
|
||||||
if (! has_default)
|
|
||||||
it= new Item_null(); /* QQ Set to the type with null_value? */
|
|
||||||
in = new sp_instr_set(lex->sphead->instructions(),
|
|
||||||
ctx,
|
|
||||||
off,
|
|
||||||
it, type, lex,
|
|
||||||
(i == max - 1));
|
|
||||||
|
|
||||||
/*
|
|
||||||
The last instruction is assigned to be responsible for
|
|
||||||
freeing LEX.
|
|
||||||
*/
|
|
||||||
lex->sphead->add_instr(in);
|
|
||||||
ctx->set_default(off, it);
|
|
||||||
}
|
}
|
||||||
ctx->declare_var_boundary(0);
|
|
||||||
|
for (uint i = num_vars-$2 ; i < num_vars ; i++)
|
||||||
|
{
|
||||||
|
uint var_idx= pctx->pvar_context2index(i);
|
||||||
|
sp_pvar_t *pvar= pctx->find_pvar(var_idx);
|
||||||
|
|
||||||
|
if (!pvar)
|
||||||
|
YYABORT;
|
||||||
|
|
||||||
|
pvar->type= var_type;
|
||||||
|
pvar->dflt= dflt_value_item;
|
||||||
|
|
||||||
|
if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
|
||||||
|
&pvar->field_def))
|
||||||
|
{
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pvar->field_def.field_name= pvar->name.str;
|
||||||
|
pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||||||
|
|
||||||
|
/* The last instruction is responsible for freeing LEX. */
|
||||||
|
|
||||||
|
lex->sphead->add_instr(
|
||||||
|
new sp_instr_set(lex->sphead->instructions(), pctx, var_idx,
|
||||||
|
dflt_value_item, var_type, lex,
|
||||||
|
(i == num_vars - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pctx->declare_var_boundary(0);
|
||||||
lex->sphead->restore_lex(YYTHD);
|
lex->sphead->restore_lex(YYTHD);
|
||||||
|
|
||||||
$$.vars= $2;
|
$$.vars= $2;
|
||||||
$$.conds= $$.hndlrs= $$.curs= 0;
|
$$.conds= $$.hndlrs= $$.curs= 0;
|
||||||
}
|
}
|
||||||
|
@ -1857,6 +1881,8 @@ sp_hcond:
|
||||||
sp_decl_idents:
|
sp_decl_idents:
|
||||||
ident
|
ident
|
||||||
{
|
{
|
||||||
|
/* NOTE: field definition is filled in sp_decl section. */
|
||||||
|
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_pcontext *spc= lex->spcont;
|
sp_pcontext *spc= lex->spcont;
|
||||||
|
|
||||||
|
@ -1870,6 +1896,8 @@ sp_decl_idents:
|
||||||
}
|
}
|
||||||
| sp_decl_idents ',' ident
|
| sp_decl_idents ',' ident
|
||||||
{
|
{
|
||||||
|
/* NOTE: field definition is filled in sp_decl section. */
|
||||||
|
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_pcontext *spc= lex->spcont;
|
sp_pcontext *spc= lex->spcont;
|
||||||
|
|
||||||
|
@ -1947,8 +1975,8 @@ sp_proc_stmt:
|
||||||
{
|
{
|
||||||
sp_instr_freturn *i;
|
sp_instr_freturn *i;
|
||||||
|
|
||||||
i= new sp_instr_freturn(sp->instructions(), lex->spcont,
|
i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3,
|
||||||
$3, sp->m_returns, lex);
|
sp->m_return_field_def.sql_type, lex);
|
||||||
sp->add_instr(i);
|
sp->add_instr(i);
|
||||||
sp->m_flags|= sp_head::HAS_RETURN;
|
sp->m_flags|= sp_head::HAS_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -1964,25 +1992,27 @@ sp_proc_stmt:
|
||||||
{ Lex->sphead->reset_lex(YYTHD); }
|
{ Lex->sphead->reset_lex(YYTHD); }
|
||||||
expr WHEN_SYM
|
expr WHEN_SYM
|
||||||
{
|
{
|
||||||
/* We "fake" this by using an anonymous variable which we
|
|
||||||
set to the expression. Note that all WHENs are evaluate
|
|
||||||
at the same frame level, so we then know that it's the
|
|
||||||
top-most variable in the frame. */
|
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
uint offset= lex->spcont->current_pvars();
|
sp_head *sp= lex->sphead;
|
||||||
sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
|
sp_pcontext *parsing_ctx= lex->spcont;
|
||||||
lex->spcont, offset, $3,
|
int case_expr_id= parsing_ctx->register_case_expr();
|
||||||
MYSQL_TYPE_STRING, lex, TRUE);
|
|
||||||
LEX_STRING dummy={(char*)"", 0};
|
if (parsing_ctx->push_case_expr_id(case_expr_id))
|
||||||
|
YYABORT;
|
||||||
lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
|
|
||||||
lex->sphead->add_instr(i);
|
sp->add_instr(
|
||||||
lex->sphead->m_flags|= sp_head::IN_SIMPLE_CASE;
|
new sp_instr_set_case_expr(sp->instructions(),
|
||||||
lex->sphead->restore_lex(YYTHD);
|
parsing_ctx,
|
||||||
|
case_expr_id,
|
||||||
|
$3,
|
||||||
|
lex));
|
||||||
|
|
||||||
|
sp->m_flags|= sp_head::IN_SIMPLE_CASE;
|
||||||
|
sp->restore_lex(YYTHD);
|
||||||
}
|
}
|
||||||
sp_case END CASE_SYM
|
sp_case END CASE_SYM
|
||||||
{
|
{
|
||||||
Lex->spcont->pop_pvar();
|
Lex->spcont->pop_case_expr_id();
|
||||||
}
|
}
|
||||||
| sp_labeled_control
|
| sp_labeled_control
|
||||||
{}
|
{}
|
||||||
|
@ -2293,20 +2323,20 @@ sp_case:
|
||||||
i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
|
i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
|
||||||
else
|
else
|
||||||
{ /* Simple case: <caseval> = <whenval> */
|
{ /* Simple case: <caseval> = <whenval> */
|
||||||
LEX_STRING ivar;
|
|
||||||
|
|
||||||
ivar.str= (char *)"_tmp_";
|
Item_case_expr *var;
|
||||||
ivar.length= 5;
|
Item *expr;
|
||||||
Item_splocal *var= new Item_splocal(ivar,
|
|
||||||
ctx->current_pvars()-1);
|
var= new Item_case_expr(ctx->get_current_case_expr_id());
|
||||||
|
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
if (var)
|
if (var)
|
||||||
var->owner= sp;
|
var->m_sp= sp;
|
||||||
#endif
|
#endif
|
||||||
Item *expr= new Item_func_eq(var, $2);
|
|
||||||
|
expr= new Item_func_eq(var, $2);
|
||||||
|
|
||||||
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
|
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
|
||||||
lex->variables_used= 1;
|
|
||||||
}
|
}
|
||||||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||||||
sp->add_instr(i);
|
sp->add_instr(i);
|
||||||
|
@ -4401,11 +4431,9 @@ simple_expr:
|
||||||
{
|
{
|
||||||
if ($3->is_splocal())
|
if ($3->is_splocal())
|
||||||
{
|
{
|
||||||
LEX_STRING *name;
|
|
||||||
Item_splocal *il= static_cast<Item_splocal *>($3);
|
Item_splocal *il= static_cast<Item_splocal *>($3);
|
||||||
|
|
||||||
name= il->my_name(NULL);
|
my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
|
||||||
my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str);
|
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
$$= new Item_default_value(Lex->current_context(), $3);
|
$$= new Item_default_value(Lex->current_context(), $3);
|
||||||
|
@ -5873,7 +5901,7 @@ select_var_ident:
|
||||||
var_list.push_back(var= new my_var($1,1,t->offset,t->type));
|
var_list.push_back(var= new my_var($1,1,t->offset,t->type));
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
if (var)
|
if (var)
|
||||||
var->owner= lex->sphead;
|
var->sp= lex->sphead;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7175,11 +7203,12 @@ simple_ident:
|
||||||
{
|
{
|
||||||
/* We're compiling a stored procedure and found a variable */
|
/* We're compiling a stored procedure and found a variable */
|
||||||
Item_splocal *splocal;
|
Item_splocal *splocal;
|
||||||
splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev -
|
splocal= new Item_splocal($1, spv->offset, spv->type,
|
||||||
|
lex->tok_start_prev -
|
||||||
lex->sphead->m_tmp_query);
|
lex->sphead->m_tmp_query);
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
if (splocal)
|
if (splocal)
|
||||||
splocal->owner= lex->sphead;
|
splocal->m_sp= lex->sphead;
|
||||||
#endif
|
#endif
|
||||||
$$ = (Item*) splocal;
|
$$ = (Item*) splocal;
|
||||||
lex->variables_used= 1;
|
lex->variables_used= 1;
|
||||||
|
|
Loading…
Add table
Reference in a new issue