mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
Merge istruewing@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/mydev/mysql-5.0-bug10932 configure.in: Auto merged sql/mysql_priv.h: Auto merged
This commit is contained in:
commit
e2bf3b211b
52 changed files with 4728 additions and 1286 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
#shift
|
||||
FROM=$USER@mysql.com
|
||||
INTERNALS=internals@lists.mysql.com
|
||||
COMMITS=commits@lists.mysql.com
|
||||
DOCS=docs-commit@mysql.com
|
||||
LIMIT=10000
|
||||
VERSION="5.0"
|
||||
|
@ -61,14 +61,14 @@ EOF
|
|||
) | /usr/sbin/sendmail -t
|
||||
|
||||
#++
|
||||
# internals@ mail
|
||||
# commits@ mail
|
||||
#--
|
||||
echo "Notifying internals list at $INTERNALS"
|
||||
echo "Notifying commits list at $COMMITS"
|
||||
(
|
||||
cat <<EOF
|
||||
List-ID: <bk.mysql-$VERSION>
|
||||
From: $FROM
|
||||
To: $INTERNALS
|
||||
To: $COMMITS
|
||||
Subject: bk commit into $VERSION tree ($CHANGESET)$BS
|
||||
X-CSetKey: <$CSETKEY>
|
||||
$BH
|
||||
|
|
|
@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
|
|||
AC_CANONICAL_SYSTEM
|
||||
# The Docs Makefile.am parses this line!
|
||||
# remember to also change ndb version below and update version.c in ndb
|
||||
AM_INIT_AUTOMAKE(mysql, 5.0.17)
|
||||
AM_INIT_AUTOMAKE(mysql, 5.0.18)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
PROTOCOL_VERSION=10
|
||||
|
|
|
@ -341,6 +341,7 @@ long SSL_CTX_sess_set_cache_size(SSL_CTX*, long);
|
|||
long SSL_CTX_set_tmp_dh(SSL_CTX*, DH*);
|
||||
|
||||
void OpenSSL_add_all_algorithms(void);
|
||||
void SSL_library_init();
|
||||
void SSLeay_add_ssl_algorithms(void);
|
||||
|
||||
|
||||
|
|
|
@ -648,6 +648,10 @@ void OpenSSL_add_all_algorithms() // compatibility only
|
|||
{}
|
||||
|
||||
|
||||
void SSL_library_init() // compatibility only
|
||||
{}
|
||||
|
||||
|
||||
DH* DH_new(void)
|
||||
{
|
||||
DH* dh = new (ys) DH;
|
||||
|
|
|
@ -117,6 +117,9 @@ typedef unsigned long long my_ulonglong;
|
|||
|
||||
#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0)
|
||||
|
||||
/* backward compatibility define - to be removed eventually */
|
||||
#define ER_WARN_DATA_TRUNCATED WARN_DATA_TRUNCATED
|
||||
|
||||
typedef struct st_mysql_rows {
|
||||
struct st_mysql_rows *next; /* list of rows */
|
||||
MYSQL_ROW data;
|
||||
|
|
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);
|
||||
CREATE PROCEDURE sp1()
|
||||
BEGIN
|
||||
DECLARE a CHAR(1);
|
||||
DECLARE a CHAR(2) CHARSET ujis;
|
||||
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
||||
OPEN cur1;
|
||||
FETCH cur1 INTO a;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
drop database if exists mysqltest1;
|
||||
create schema foo;
|
||||
show create schema foo;
|
||||
Database Create Database
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
drop table if exists t1,t2;
|
||||
drop table if exists t1aa,t2aa;
|
||||
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.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
|
||||
flush privileges;
|
||||
|
|
|
@ -10,5 +10,5 @@ user()
|
|||
#
|
||||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root # test Sleep # NULL
|
||||
# root # test Query # NULL show processlist
|
||||
<id> root <host> test <command> <time> <state> <info>
|
||||
<id> root <host> test <command> <time> <state> <info>
|
||||
|
|
|
@ -25,6 +25,7 @@ count(*)
|
|||
select count(*) from t2;
|
||||
count(*)
|
||||
0
|
||||
drop procedure if exists p1;
|
||||
create procedure p1()
|
||||
begin
|
||||
declare done integer default 0;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
drop procedure if exists p1|
|
||||
drop procedure if exists p2|
|
||||
create procedure p1()
|
||||
begin
|
||||
prepare stmt from "select 1";
|
||||
|
|
|
@ -768,7 +768,7 @@ BEGIN
|
|||
OPTIMIZE TABLE t1;
|
||||
RETURN 1;
|
||||
END|
|
||||
ERROR 0A000: OPTIMIZE TABLE is not allowed in stored procedures
|
||||
ERROR 0A000: Not allowed to return a result set from a function
|
||||
DROP FUNCTION IF EXISTS bug12995|
|
||||
CREATE FUNCTION bug12995() RETURNS INT
|
||||
BEGIN
|
||||
|
@ -981,6 +981,8 @@ END |
|
|||
drop table t1|
|
||||
drop function bug_13627_f|
|
||||
drop function if exists bug12329;
|
||||
Warnings:
|
||||
Note 1305 FUNCTION bug12329 does not exist
|
||||
create table t1 as select 1 a;
|
||||
create table t2 as select 1 a;
|
||||
create function bug12329() returns int return (select a from t1);
|
||||
|
@ -1055,3 +1057,34 @@ Db Name Type Definer Modified Created Security_type Comment
|
|||
mysqltest2 p1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
|
||||
drop database mysqltest2;
|
||||
use test;
|
||||
DROP FUNCTION IF EXISTS bug13012|
|
||||
CREATE FUNCTION bug13012() RETURNS INT
|
||||
BEGIN
|
||||
REPAIR TABLE t1;
|
||||
RETURN 1;
|
||||
END|
|
||||
ERROR 0A000: Not allowed to return a result set from a function
|
||||
CREATE FUNCTION bug13012() RETURNS INT
|
||||
BEGIN
|
||||
BACKUP TABLE t1 TO '/tmp';
|
||||
RETURN 1;
|
||||
END|
|
||||
ERROR 0A000: Not allowed to return a result set from a function
|
||||
CREATE FUNCTION bug13012() RETURNS INT
|
||||
BEGIN
|
||||
RESTORE TABLE t1 FROM '/tmp';
|
||||
RETURN 1;
|
||||
END|
|
||||
ERROR 0A000: Not allowed to return a result set from a function
|
||||
create table t1 (a int)|
|
||||
CREATE PROCEDURE bug13012_1() REPAIR TABLE t1|
|
||||
CREATE FUNCTION bug13012_2() RETURNS INT
|
||||
BEGIN
|
||||
CALL bug13012_1();
|
||||
RETURN 1;
|
||||
END|
|
||||
SELECT bug13012_2()|
|
||||
ERROR 0A000: Not allowed to return a result set from a function
|
||||
drop table t1|
|
||||
drop procedure bug13012_1|
|
||||
drop function bug13012_2|
|
||||
|
|
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("sub1b", (select max(i) from t2))|
|
||||
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 sub2("sub2")|
|
||||
select * from t1|
|
||||
id data
|
||||
sub1a 7
|
||||
sub1b 3
|
||||
sub1c 1
|
||||
sub1d 1
|
||||
sub2 6
|
||||
select sub3((select max(i) from t2))|
|
||||
|
@ -2686,7 +2686,7 @@ call bug8937()|
|
|||
s x y z
|
||||
16 3 1 6
|
||||
a
|
||||
3.2000
|
||||
3.2
|
||||
drop procedure bug8937|
|
||||
delete from t1|
|
||||
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')|
|
||||
bug9775('a') bug9775('b') bug9775('c')
|
||||
a b
|
||||
Warnings:
|
||||
Warning 1265 Data truncated for column 'bug9775('c')' at row 1
|
||||
drop function bug9775|
|
||||
create function bug9775(v1 int) returns enum('a','b') return v1|
|
||||
select bug9775(1),bug9775(2),bug9775(3)|
|
||||
bug9775(1) bug9775(2) bug9775(3)
|
||||
a b
|
||||
Warnings:
|
||||
Warning 1265 Data truncated for column 'bug9775(3)' at row 1
|
||||
drop function bug9775|
|
||||
create function bug9775(v1 char(1)) returns set('a','b') return v1|
|
||||
select 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|
|
||||
create function bug9775(v1 int) returns set('a','b') return v1|
|
||||
select bug9775(1),bug9775(2),bug9775(3),bug9775(4)|
|
||||
bug9775(1) bug9775(2) bug9775(3) bug9775(4)
|
||||
a b a,b
|
||||
Warnings:
|
||||
Warning 1265 Data truncated for column 'bug9775(4)' at row 1
|
||||
drop function bug9775|
|
||||
drop function if exists bug8861|
|
||||
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('12345678901234567')|
|
||||
Warnings:
|
||||
Warning 1265 Data truncated for column 'id' at row 1
|
||||
Warning 1265 Data truncated for column 'id' at row 2
|
||||
Warning 1265 Data truncated for column 'x' at row 1
|
||||
call bug9004_2('12345678901234567890')|
|
||||
Warnings:
|
||||
Warning 1265 Data truncated for column 'id' at row 1
|
||||
Warning 1265 Data truncated for column 'id' at row 2
|
||||
Warning 1265 Data truncated for column 'x' at row 1
|
||||
delete from t1|
|
||||
drop procedure bug9004_1|
|
||||
drop procedure bug9004_2|
|
||||
|
@ -3527,14 +3534,15 @@ end|
|
|||
call bug12589_1()|
|
||||
Table Create Table
|
||||
tm1 CREATE TEMPORARY TABLE `tm1` (
|
||||
`spv1` decimal(1,0) unsigned default NULL
|
||||
`spv1` decimal(3,3) default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
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()|
|
||||
Table Create Table
|
||||
tm1 CREATE TEMPORARY TABLE `tm1` (
|
||||
`spv1` decimal(6,3) unsigned default NULL
|
||||
`spv1` decimal(6,3) default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
call bug12589_3()|
|
||||
Table Create Table
|
||||
|
@ -4016,34 +4024,37 @@ create procedure bug14643_1()
|
|||
begin
|
||||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||
begin
|
||||
declare v int default x;
|
||||
declare v int default undefined_var;
|
||||
if v = 1 then
|
||||
select 1;
|
||||
else
|
||||
select 2;
|
||||
select v, isnull(v);
|
||||
end if;
|
||||
end;
|
||||
end|
|
||||
create procedure bug14643_2()
|
||||
begin
|
||||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||
case x
|
||||
case undefined_var
|
||||
when 1 then
|
||||
select 1;
|
||||
else
|
||||
select 2;
|
||||
end case;
|
||||
select undefined_var;
|
||||
end|
|
||||
call bug14643_1()|
|
||||
Handler
|
||||
boo
|
||||
2
|
||||
2
|
||||
v isnull(v)
|
||||
NULL 1
|
||||
call bug14643_2()|
|
||||
Handler
|
||||
boo
|
||||
2
|
||||
2
|
||||
Handler
|
||||
boo
|
||||
drop procedure bug14643_1|
|
||||
drop procedure bug14643_2|
|
||||
drop procedure if exists bug14304|
|
||||
|
@ -4100,8 +4111,6 @@ x
|
|||
4711
|
||||
drop procedure bug14376|
|
||||
drop procedure if exists p1|
|
||||
Warnings:
|
||||
Note 1305 PROCEDURE p1 does not exist
|
||||
drop table if exists t1|
|
||||
create table t1 (a varchar(255))|
|
||||
insert into t1 (a) values ("a - table column")|
|
||||
|
@ -4153,6 +4162,89 @@ A local variable in a nested compound statement takes precedence over table colu
|
|||
a - local variable in a nested compound statement
|
||||
A local variable in a nested compound statement takes precedence over table column in cursors
|
||||
a - local variable in a nested compound statement
|
||||
drop procedure p1|
|
||||
drop procedure if exists bug13012|
|
||||
create procedure bug13012()
|
||||
BEGIN
|
||||
REPAIR TABLE t1;
|
||||
BACKUP TABLE t1 to '../tmp';
|
||||
DROP TABLE t1;
|
||||
RESTORE TABLE t1 FROM '../tmp';
|
||||
END|
|
||||
call bug13012()|
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 backup status OK
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 restore status OK
|
||||
drop procedure bug13012|
|
||||
create view v1 as select * from t1|
|
||||
create procedure bug13012()
|
||||
BEGIN
|
||||
REPAIR TABLE t1,t2,t3,v1;
|
||||
OPTIMIZE TABLE t1,t2,t3,v1;
|
||||
ANALYZE TABLE t1,t2,t3,v1;
|
||||
END|
|
||||
call bug13012()|
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
test.t2 repair status OK
|
||||
test.t3 repair error Table 'test.t3' doesn't exist
|
||||
test.v1 repair error 'test.v1' is not BASE TABLE
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize status OK
|
||||
test.t2 optimize status OK
|
||||
test.t3 optimize error Table 'test.t3' doesn't exist
|
||||
test.v1 optimize error 'test.v1' is not BASE TABLE
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status Table is already up to date
|
||||
test.t2 analyze status Table is already up to date
|
||||
test.t3 analyze error Table 'test.t3' doesn't exist
|
||||
test.v1 analyze error 'test.v1' is not BASE TABLE
|
||||
Warnings:
|
||||
Error 1347 'test.v1' is not BASE TABLE
|
||||
call bug13012()|
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
test.t2 repair status OK
|
||||
test.t3 repair error Table 'test.t3' doesn't exist
|
||||
test.v1 repair error 'test.v1' is not BASE TABLE
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize status OK
|
||||
test.t2 optimize status OK
|
||||
test.t3 optimize error Table 'test.t3' doesn't exist
|
||||
test.v1 optimize error 'test.v1' is not BASE TABLE
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status Table is already up to date
|
||||
test.t2 analyze status Table is already up to date
|
||||
test.t3 analyze error Table 'test.t3' doesn't exist
|
||||
test.v1 analyze error 'test.v1' is not BASE TABLE
|
||||
Warnings:
|
||||
Error 1347 'test.v1' is not BASE TABLE
|
||||
call bug13012()|
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
test.t2 repair status OK
|
||||
test.t3 repair error Table 'test.t3' doesn't exist
|
||||
test.v1 repair error 'test.v1' is not BASE TABLE
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize status OK
|
||||
test.t2 optimize status OK
|
||||
test.t3 optimize error Table 'test.t3' doesn't exist
|
||||
test.v1 optimize error 'test.v1' is not BASE TABLE
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status Table is already up to date
|
||||
test.t2 analyze status Table is already up to date
|
||||
test.t3 analyze error Table 'test.t3' doesn't exist
|
||||
test.v1 analyze error 'test.v1' is not BASE TABLE
|
||||
Warnings:
|
||||
Error 1347 'test.v1' is not BASE TABLE
|
||||
drop procedure bug13012|
|
||||
drop view v1;
|
||||
select * from t1|
|
||||
a
|
||||
a - table column
|
||||
drop schema if exists mysqltest1|
|
||||
Warnings:
|
||||
Note 1008 Can't drop database 'mysqltest1'; database doesn't exist
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using_big_test
|
||||
0
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (id INTEGER);
|
||||
CREATE TABLE t2 (id INTEGER);
|
||||
INSERT INTO t1 (id) VALUES (1), (1), (1),(1);
|
||||
|
@ -40,19 +39,19 @@ AVG(DISTINCT id)
|
|||
512.5000
|
||||
SELECT SUM(DISTINCT id)/COUNT(DISTINCT id) FROM t1 GROUP BY id % 13;
|
||||
SUM(DISTINCT id)/COUNT(DISTINCT id)
|
||||
513.50000
|
||||
508.00000
|
||||
509.00000
|
||||
510.00000
|
||||
511.00000
|
||||
512.00000
|
||||
513.00000
|
||||
514.00000
|
||||
515.00000
|
||||
516.00000
|
||||
517.00000
|
||||
511.50000
|
||||
512.50000
|
||||
513.5000
|
||||
508.0000
|
||||
509.0000
|
||||
510.0000
|
||||
511.0000
|
||||
512.0000
|
||||
513.0000
|
||||
514.0000
|
||||
515.0000
|
||||
516.0000
|
||||
517.0000
|
||||
511.5000
|
||||
512.5000
|
||||
INSERT INTO t1 SELECT id+1024 FROM t1;
|
||||
INSERT INTO t1 SELECT id+2048 FROM t1;
|
||||
INSERT INTO t1 SELECT id+4096 FROM t1;
|
||||
|
|
|
@ -1,11 +1,26 @@
|
|||
drop procedure if exists sp1;
|
||||
create procedure sp1 () begin
|
||||
declare v1, v2, v3, v4 decimal(16,12); declare v5 int;
|
||||
set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0;
|
||||
while v5 < 100000 do
|
||||
set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1;
|
||||
end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;//
|
||||
CREATE PROCEDURE sp1()
|
||||
BEGIN
|
||||
DECLARE v1, v2, v3, v4 DECIMAL(28,12);
|
||||
DECLARE v3_2, v4_2 DECIMAL(28, 12);
|
||||
DECLARE counter INT;
|
||||
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()//
|
||||
v1 v2 v3 * 0.000000000001 v4 * 0.000000000001
|
||||
1.000000100000 1.999999900000 1.000000100000 1.999999900000
|
||||
v1 v2 v3 v3_2 v4 v4_2
|
||||
1.000000100000 1.999999900000 1000000100000.000000000000 1.000000100000 1999999900000.000000000000 1.999999900000
|
||||
drop procedure sp1;
|
||||
|
|
|
@ -2383,20 +2383,25 @@ CREATE TABLE t1(id INT);
|
|||
CREATE VIEW v1 AS SELECT id FROM t1;
|
||||
OPTIMIZE TABLE v1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 optimize note Unknown table 'test.v1'
|
||||
test.v1 optimize error 'test.v1' is not BASE TABLE
|
||||
Warnings:
|
||||
Error 1347 'test.v1' is not BASE TABLE
|
||||
ANALYZE TABLE v1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 analyze note Unknown table 'test.v1'
|
||||
test.v1 analyze error 'test.v1' is not BASE TABLE
|
||||
Warnings:
|
||||
Error 1347 'test.v1' is not BASE TABLE
|
||||
REPAIR TABLE v1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 repair note Unknown table 'test.v1'
|
||||
test.v1 repair error 'test.v1' is not BASE TABLE
|
||||
Warnings:
|
||||
Error 1347 'test.v1' is not BASE TABLE
|
||||
DROP TABLE t1;
|
||||
OPTIMIZE TABLE v1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 optimize note Unknown table 'test.v1'
|
||||
test.v1 optimize error 'test.v1' is not BASE TABLE
|
||||
Warnings:
|
||||
Error 1146 Table 'test.t1' doesn't exist
|
||||
Error 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
Error 1347 'test.v1' is not BASE TABLE
|
||||
DROP VIEW v1;
|
||||
create definer = current_user() sql security invoker view v1 as select 1;
|
||||
show create view v1;
|
||||
|
|
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
|
@ -52,5 +52,6 @@ unlock tables;
|
|||
connection con1;
|
||||
reap;
|
||||
drop table t5;
|
||||
--system rm $MYSQL_TEST_DIR/var/tmp/t?.*
|
||||
|
||||
# End of 4.1 tests
|
||||
|
|
|
@ -1170,7 +1170,7 @@ INSERT INTO t1 VALUES(_ujis 0xA4A2);
|
|||
DELIMITER |;
|
||||
CREATE PROCEDURE sp1()
|
||||
BEGIN
|
||||
DECLARE a CHAR(1);
|
||||
DECLARE a CHAR(2) CHARSET ujis;
|
||||
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
||||
OPEN cur1;
|
||||
FETCH cur1 INTO a;
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
#
|
||||
# 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;
|
||||
show create schema foo;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
drop table if exists t1,t2;
|
||||
drop table if exists t1aa,t2aa;
|
||||
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.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, );
|
||||
--replace_column 1 #
|
||||
select user();
|
||||
--replace_column 1 # 6 # 3 #
|
||||
--replace_column 1 <id> 3 <host> 5 <command> 6 <time> 7 <state> 8 <info>
|
||||
show processlist;
|
||||
connection default;
|
||||
|
|
|
@ -52,6 +52,9 @@ while ($1)
|
|||
--enable_query_log
|
||||
select count(*) from t1;
|
||||
select count(*) from t2;
|
||||
--disable_warnings
|
||||
drop procedure if exists p1;
|
||||
--enable_warnings
|
||||
delimiter |;
|
||||
create procedure p1()
|
||||
begin
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
delimiter |;
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists p1|
|
||||
drop procedure if exists p2|
|
||||
--enable_warnings
|
||||
|
||||
######################################################################
|
||||
# Test Dynamic SQL in stored procedures. #############################
|
||||
######################################################################
|
||||
|
|
|
@ -1095,7 +1095,7 @@ delimiter |;
|
|||
--disable_warnings
|
||||
DROP FUNCTION IF EXISTS bug12953|
|
||||
--enable_warnings
|
||||
--error ER_SP_BADSTATEMENT
|
||||
--error ER_SP_NO_RETSET
|
||||
CREATE FUNCTION bug12953() RETURNS INT
|
||||
BEGIN
|
||||
OPTIMIZE TABLE t1;
|
||||
|
@ -1410,7 +1410,6 @@ delimiter ;|
|
|||
|
||||
# BUG#12329: "Bogus error msg when executing PS with stored procedure after
|
||||
# SP was re-created". See also test for related bug#13399 in trigger.test
|
||||
--disable_warnings
|
||||
drop function if exists bug12329;
|
||||
--enable_warnings
|
||||
create table t1 as select 1 a;
|
||||
|
@ -1518,6 +1517,44 @@ show procedure status;
|
|||
drop database mysqltest2;
|
||||
use test;
|
||||
|
||||
#
|
||||
# Bug#13012 "SP: REPAIR/BACKUP/RESTORE TABLE crashes the server"
|
||||
#
|
||||
delimiter |;
|
||||
--disable_warnings
|
||||
DROP FUNCTION IF EXISTS bug13012|
|
||||
--enable_warnings
|
||||
--error ER_SP_NO_RETSET
|
||||
CREATE FUNCTION bug13012() RETURNS INT
|
||||
BEGIN
|
||||
REPAIR TABLE t1;
|
||||
RETURN 1;
|
||||
END|
|
||||
--error ER_SP_NO_RETSET
|
||||
CREATE FUNCTION bug13012() RETURNS INT
|
||||
BEGIN
|
||||
BACKUP TABLE t1 TO '/tmp';
|
||||
RETURN 1;
|
||||
END|
|
||||
--error ER_SP_NO_RETSET
|
||||
CREATE FUNCTION bug13012() RETURNS INT
|
||||
BEGIN
|
||||
RESTORE TABLE t1 FROM '/tmp';
|
||||
RETURN 1;
|
||||
END|
|
||||
create table t1 (a int)|
|
||||
CREATE PROCEDURE bug13012_1() REPAIR TABLE t1|
|
||||
CREATE FUNCTION bug13012_2() RETURNS INT
|
||||
BEGIN
|
||||
CALL bug13012_1();
|
||||
RETURN 1;
|
||||
END|
|
||||
--error ER_SP_NO_RETSET
|
||||
SELECT bug13012_2()|
|
||||
drop table t1|
|
||||
drop procedure bug13012_1|
|
||||
drop function bug13012_2|
|
||||
delimiter ;|
|
||||
|
||||
# BUG#NNNN: New bug synopsis
|
||||
#
|
||||
|
|
|
@ -367,6 +367,7 @@ create function sub3(i int) returns int
|
|||
|
||||
call sub1("sub1a", (select 7))|
|
||||
call sub1("sub1b", (select max(i) from t2))|
|
||||
--error ER_OPERAND_COLUMNS
|
||||
call sub1("sub1c", (select i,d from t2 limit 1))|
|
||||
call sub1("sub1d", (select 1 from (select 1) a))|
|
||||
call sub2("sub2")|
|
||||
|
@ -4797,12 +4798,12 @@ begin
|
|||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||
|
||||
begin
|
||||
declare v int default x;
|
||||
declare v int default undefined_var;
|
||||
|
||||
if v = 1 then
|
||||
select 1;
|
||||
else
|
||||
select 2;
|
||||
select v, isnull(v);
|
||||
end if;
|
||||
end;
|
||||
end|
|
||||
|
@ -4811,12 +4812,14 @@ create procedure bug14643_2()
|
|||
begin
|
||||
declare continue handler for sqlexception select 'boo' as 'Handler';
|
||||
|
||||
case x
|
||||
case undefined_var
|
||||
when 1 then
|
||||
select 1;
|
||||
else
|
||||
select 2;
|
||||
end case;
|
||||
|
||||
select undefined_var;
|
||||
end|
|
||||
|
||||
call bug14643_1()|
|
||||
|
@ -4910,8 +4913,10 @@ drop procedure bug14376|
|
|||
# variable declarations. In MySQL 5.0 it's vice versa.
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop procedure if exists p1|
|
||||
drop table if exists t1|
|
||||
--enable_warnings
|
||||
create table t1 (a varchar(255))|
|
||||
insert into t1 (a) values ("a - table column")|
|
||||
create procedure p1(a varchar(255))
|
||||
|
@ -4946,6 +4951,36 @@ begin
|
|||
end;
|
||||
end|
|
||||
call p1("a - stored procedure parameter")|
|
||||
drop procedure p1|
|
||||
|
||||
#
|
||||
# Bug#13012 "SP: REPAIR/BACKUP/RESTORE TABLE crashes the server"
|
||||
#
|
||||
--disable_warnings
|
||||
drop procedure if exists bug13012|
|
||||
--enable_warnings
|
||||
create procedure bug13012()
|
||||
BEGIN
|
||||
REPAIR TABLE t1;
|
||||
BACKUP TABLE t1 to '../tmp';
|
||||
DROP TABLE t1;
|
||||
RESTORE TABLE t1 FROM '../tmp';
|
||||
END|
|
||||
call bug13012()|
|
||||
drop procedure bug13012|
|
||||
create view v1 as select * from t1|
|
||||
create procedure bug13012()
|
||||
BEGIN
|
||||
REPAIR TABLE t1,t2,t3,v1;
|
||||
OPTIMIZE TABLE t1,t2,t3,v1;
|
||||
ANALYZE TABLE t1,t2,t3,v1;
|
||||
END|
|
||||
call bug13012()|
|
||||
call bug13012()|
|
||||
call bug13012()|
|
||||
drop procedure bug13012|
|
||||
drop view v1;
|
||||
select * from t1|
|
||||
|
||||
#
|
||||
# A test case for Bug#15392 "Server crashes during prepared statement
|
||||
|
|
|
@ -12,12 +12,31 @@ drop procedure if exists sp1;
|
|||
|
||||
delimiter //;
|
||||
#
|
||||
create procedure sp1 () begin
|
||||
declare v1, v2, v3, v4 decimal(16,12); declare v5 int;
|
||||
set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0;
|
||||
while v5 < 100000 do
|
||||
set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1;
|
||||
end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;//
|
||||
CREATE PROCEDURE sp1()
|
||||
BEGIN
|
||||
DECLARE v1, v2, v3, v4 DECIMAL(28,12);
|
||||
DECLARE v3_2, v4_2 DECIMAL(28, 12);
|
||||
DECLARE counter INT;
|
||||
|
||||
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()//
|
||||
#-- 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;
|
||||
if (table)
|
||||
{
|
||||
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 type;
|
||||
|
|
18
sql/field.h
18
sql/field.h
|
@ -130,7 +130,19 @@ public:
|
|||
null_bit == field->null_bit);
|
||||
}
|
||||
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; }
|
||||
|
||||
/*
|
||||
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 sort_length() const { return 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,
|
||||
uint32 max_length, uint32 decimals,
|
||||
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():
|
||||
rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
Item *it= this_item();
|
||||
String *res= it->val_str(sp);
|
||||
|
||||
null_value= it->null_value;
|
||||
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
|
@ -854,11 +870,12 @@ String *Item_splocal::val_str(String *sp)
|
|||
str_value.set(res->ptr(), res->length(), res->charset());
|
||||
else
|
||||
res->mark_as_const();
|
||||
|
||||
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);
|
||||
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 it->is_null();
|
||||
return this_item()->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_splocal::this_item()
|
||||
{
|
||||
DBUG_ASSERT(owner == thd->spcont->owner);
|
||||
return thd->spcont->get_item(m_offset);
|
||||
DBUG_ASSERT(m_sp == m_thd->spcont->sp);
|
||||
|
||||
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_splocal::this_item_addr(THD *thd, Item **addr)
|
||||
Item_splocal::this_item_addr(THD *thd, Item **)
|
||||
{
|
||||
DBUG_ASSERT(owner == thd->spcont->owner);
|
||||
return thd->spcont->get_item_addr(m_offset);
|
||||
}
|
||||
DBUG_ASSERT(m_sp == thd->spcont->sp);
|
||||
|
||||
Item *
|
||||
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;
|
||||
return thd->spcont->get_item_addr(m_var_idx);
|
||||
}
|
||||
|
||||
|
||||
|
@ -934,7 +940,53 @@ void Item_splocal::print(String *str)
|
|||
str->reserve(m_name.length+8);
|
||||
str->append(m_name.str, m_name.length);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return set_field_to_null_with_conversions(field, no_conversions);
|
||||
}
|
||||
|
||||
/* NOTE: If null_value == FALSE, "result" must be not NULL. */
|
||||
|
||||
field->set_notnull();
|
||||
error=field->store(result->ptr(),result->length(),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); }
|
||||
static void *operator new(size_t size, MEM_ROOT *mem_root)
|
||||
{ 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, MEM_ROOT *mem_root) {}
|
||||
|
||||
|
@ -713,13 +711,13 @@ public:
|
|||
current value and pointer to current Item otherwise.
|
||||
*/
|
||||
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
|
||||
current value and pointer passed via parameter otherwise.
|
||||
*/
|
||||
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
|
||||
virtual uint cols() { return 1; }
|
||||
|
@ -748,21 +746,32 @@ public:
|
|||
|
||||
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:
|
||||
#ifndef DBUG_OFF
|
||||
|
@ -770,11 +779,74 @@ public:
|
|||
Routine to which this Item_splocal belongs. Used for checking if correct
|
||||
runtime context is used for variable handling.
|
||||
*/
|
||||
sp_head *owner;
|
||||
sp_head *m_sp;
|
||||
#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
|
||||
statement itself is in sp_instr_stmt::m_query).
|
||||
|
@ -787,78 +859,94 @@ public:
|
|||
*/
|
||||
uint pos_in_query;
|
||||
|
||||
Item_splocal(LEX_STRING name, uint offset, uint pos_in_q=0)
|
||||
: m_offset(offset), m_name(name), thd(0), pos_in_query(pos_in_q)
|
||||
{
|
||||
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;
|
||||
}
|
||||
Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx,
|
||||
enum_field_types sp_var_type, uint pos_in_q= 0);
|
||||
|
||||
bool is_splocal() { return 1; } /* Needed for error checking */
|
||||
|
||||
Item *this_item();
|
||||
const Item *this_item() const;
|
||||
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 make_field(Send_field *field)
|
||||
{
|
||||
Item *it= this_item();
|
||||
public:
|
||||
inline const LEX_STRING *my_name() const;
|
||||
|
||||
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 uint get_var_idx() const;
|
||||
|
||||
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);
|
||||
}
|
||||
inline enum Type type() const;
|
||||
inline Item_result result_type() const;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
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).
|
||||
|
@ -885,7 +973,6 @@ public:
|
|||
}
|
||||
|
||||
bool fix_fields(THD *, Item **);
|
||||
void cleanup();
|
||||
|
||||
enum Type type() const;
|
||||
double val_real();
|
||||
|
|
|
@ -4716,7 +4716,7 @@ Item_func_sp::sp_result_field(void) const
|
|||
share->table_cache_key = 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);
|
||||
}
|
||||
|
||||
|
@ -4729,17 +4729,17 @@ Item_func_sp::sp_result_field(void) const
|
|||
1 value = NULL or error
|
||||
*/
|
||||
|
||||
int
|
||||
bool
|
||||
Item_func_sp::execute(Field **flp)
|
||||
{
|
||||
Item *it;
|
||||
THD *thd= current_thd;
|
||||
Field *f;
|
||||
if (execute(&it))
|
||||
{
|
||||
null_value= 1;
|
||||
context->process_error(current_thd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Get field in virtual tmp table to store result. Create the field if
|
||||
invoked first time.
|
||||
*/
|
||||
|
||||
if (!(f= *flp))
|
||||
{
|
||||
*flp= f= sp_result_field();
|
||||
|
@ -4748,20 +4748,33 @@ Item_func_sp::execute(Field **flp)
|
|||
f->null_ptr= (uchar *)&null_value;
|
||||
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
|
||||
Item_func_sp::execute(Item **itp)
|
||||
bool
|
||||
Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
|
||||
{
|
||||
DBUG_ENTER("Item_func_sp::execute");
|
||||
THD *thd= current_thd;
|
||||
int res= -1;
|
||||
bool err_status= TRUE;
|
||||
Sub_statement_state statement_state;
|
||||
Security_context *save_security_ctx= thd->security_ctx, *save_ctx_func;
|
||||
|
||||
DBUG_ENTER("Item_func_sp::execute_impl");
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (context->security_ctx)
|
||||
{
|
||||
|
@ -4778,7 +4791,7 @@ Item_func_sp::execute(Item **itp)
|
|||
function call into binlog.
|
||||
*/
|
||||
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);
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
|
@ -4788,7 +4801,7 @@ error:
|
|||
#else
|
||||
error:
|
||||
#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");
|
||||
|
||||
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)
|
||||
res= Item_func::tmp_table_field(t_arg);
|
||||
|
|
|
@ -1374,8 +1374,8 @@ private:
|
|||
Field *result_field;
|
||||
char result_buf[64];
|
||||
|
||||
int execute(Item **itp);
|
||||
int execute(Field **flp);
|
||||
bool execute(Field **flp);
|
||||
bool execute_impl(THD *thd, Field *return_value_fld);
|
||||
Field *sp_result_field(void) const;
|
||||
|
||||
public:
|
||||
|
|
|
@ -664,6 +664,7 @@ bool mysql_assign_to_keycache(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,
|
||||
KEY_CACHE *dst_cache);
|
||||
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
|
||||
|
||||
bool mysql_xa_recover(THD *thd);
|
||||
|
||||
|
@ -1103,8 +1104,8 @@ void unhex_type2(TYPELIB *lib);
|
|||
uint check_word(TYPELIB *lib, const char *val, const char *end,
|
||||
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"
|
||||
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
|
||||
|
|
|
@ -4590,7 +4590,7 @@ ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 21000
|
|||
nla "De gebruikte SELECT commando's hebben een verschillend aantal kolommen"
|
||||
eng "The used SELECT statements have a different number of columns"
|
||||
est "Tulpade arv kasutatud SELECT lausetes ei kattu"
|
||||
ger "Die verwendeten SELECT-Befehle liefern eine unterschiedliche Anzahl von Feldern zurück"
|
||||
ger "Die verwendeten SELECT-Befehle liefern unterschiedliche Anzahlen von Feldern zurück"
|
||||
ita "La SELECT utilizzata ha un numero di colonne differente"
|
||||
por "Os comandos SELECT usados têm diferente número de colunas"
|
||||
rus "éÓÐÏÌØÚÏ×ÁÎÎÙÅ ÏÐÅÒÁÔÏÒÙ ×ÙÂÏÒËÉ (SELECT) ÄÁÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
|
||||
|
@ -5274,7 +5274,7 @@ ER_VIEW_SELECT_TMPTABLE
|
|||
ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.64s'"
|
||||
ER_VIEW_WRONG_LIST
|
||||
eng "View's SELECT and view's field list have different column counts"
|
||||
ger "SELECT- und Feldliste der Views haben eine unterschiedliche Anzahl von Spalten"
|
||||
ger "SELECT- und Feldliste der Views haben unterschiedliche Anzahlen von Spalten"
|
||||
rus "View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
|
||||
ukr "View SELECT ¦ ÐÅÒÅÌ¦Ë ÓÔÏ×ÂÃ¦× view ÍÁÀÔØ Ò¦ÚÎÕ Ë¦ÌØ˦ÓÔØ ÓËÏ×Âæ×"
|
||||
ER_WARN_VIEW_MERGE
|
||||
|
@ -5485,7 +5485,7 @@ ER_CANT_CREATE_GEOMETRY_OBJECT 22003
|
|||
ger "Kann kein Geometrieobjekt aus den Daten machen, die Sie dem GEOMETRY-Feld übergeben haben"
|
||||
ER_FAILED_ROUTINE_BREAK_BINLOG
|
||||
eng "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes"
|
||||
ger "Eine Routine, die weder NO SQL noch READS SQL DATA in der Deklaration hat, schlug fehl und Binärlogging ist aktiv. Wenn Nicht-Transaktions-Tabellen atualisiert wurden, enthält das Binärlog ihre Änderungen nicht"
|
||||
ger "Eine Routine, die weder NO SQL noch READS SQL DATA in der Deklaration hat, schlug fehl und Binärlogging ist aktiv. Wenn Nicht-Transaktions-Tabellen aktualisiert wurden, enthält das Binärlog ihre Änderungen nicht"
|
||||
ER_BINLOG_UNSAFE_ROUTINE
|
||||
eng "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)"
|
||||
ger "Diese Routine hat weder DETERMINISTIC, NO SQL noch READS SQL DATA in der Deklaration und Binärlogging ist aktiv (*vielleicht* sollten Sie die weniger sichere Variable log_bin_trust_routine_creators verwenden)"
|
||||
|
@ -5595,10 +5595,13 @@ ER_SP_BAD_VAR_SHADOW 42000
|
|||
eng "Variable '%-.64s' must be quoted with `...`, or renamed"
|
||||
ger "Variable '%-.64s' muss mit `...` geschützt oder aber umbenannt werden"
|
||||
ER_TRG_NO_DEFINER
|
||||
eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
|
||||
eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
|
||||
ger "Kein Definierer-Attribut für Trigger '%-.64s'.'%-.64s'. Der Trigger wird mit der Autorisierung des Aufrufers aktiviert, der möglicherweise keine zureichenden Berechtigungen hat. Bitte legen Sie den Trigger neu an."
|
||||
ER_OLD_FILE_FORMAT
|
||||
eng "'%-.64s' has an old format, you should re-create the '%s' object(s)"
|
||||
eng "'%-.64s' has an old format, you should re-create the '%s' object(s)"
|
||||
ger "'%-.64s' hat altes Format, Sie sollten die '%s'-Objekt(e) neu erzeugen"
|
||||
ER_SP_RECURSION_LIMIT
|
||||
eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.64s"
|
||||
ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.64s überschritten"
|
||||
ER_SP_PROC_TABLE_CORRUPT
|
||||
eng "Failed to load routine %s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
|
||||
|
|
|
@ -467,7 +467,7 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
|
|||
bzero(&table, sizeof(table));
|
||||
table.in_use= thd;
|
||||
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);
|
||||
delete field;
|
||||
}
|
||||
|
|
956
sql/sp_head.cc
956
sql/sp_head.cc
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,9 @@
|
|||
Item_result
|
||||
sp_map_result_type(enum enum_field_types type);
|
||||
|
||||
Item::Type
|
||||
sp_map_item_type(enum enum_field_types type);
|
||||
|
||||
uint
|
||||
sp_get_flags_for_command(LEX *lex);
|
||||
|
||||
|
@ -123,12 +126,9 @@ public:
|
|||
/* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
|
||||
int m_type;
|
||||
uint m_flags; // Boolean attributes of a stored routine
|
||||
enum enum_field_types m_returns; // For FUNCTIONs only
|
||||
Field::geometry_type m_geom_returns;
|
||||
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
|
||||
|
||||
create_field m_return_field_def; /* This is used for FUNCTIONs only. */
|
||||
|
||||
uchar *m_tmp_query; // Temporary pointer to sub query string
|
||||
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
|
||||
st_sp_chistics *m_chistics;
|
||||
|
@ -202,9 +202,6 @@ public:
|
|||
void
|
||||
init_strings(THD *thd, LEX *lex, sp_name *name);
|
||||
|
||||
TYPELIB *
|
||||
create_typelib(List<String> *src);
|
||||
|
||||
int
|
||||
create(THD *thd);
|
||||
|
||||
|
@ -214,10 +211,10 @@ public:
|
|||
void
|
||||
destroy();
|
||||
|
||||
int
|
||||
execute_function(THD *thd, Item **args, uint argcount, Item **resp);
|
||||
bool
|
||||
execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
|
||||
|
||||
int
|
||||
bool
|
||||
execute_procedure(THD *thd, List<Item> *args);
|
||||
|
||||
int
|
||||
|
@ -278,7 +275,12 @@ public:
|
|||
|
||||
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,
|
||||
st_sp_chistics *chistics, ulong sql_mode);
|
||||
|
@ -363,7 +365,7 @@ private:
|
|||
*/
|
||||
HASH m_sptabs;
|
||||
|
||||
int
|
||||
bool
|
||||
execute(THD *thd);
|
||||
|
||||
/*
|
||||
|
@ -1074,6 +1076,31 @@ private:
|
|||
}; // 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
|
||||
bool
|
||||
sp_change_security_context(THD *thd, sp_head *sp,
|
||||
|
@ -1086,8 +1113,10 @@ TABLE_LIST *
|
|||
sp_add_to_query_tables(THD *thd, LEX *lex,
|
||||
const char *db, const char *name,
|
||||
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,
|
||||
Item *reuse, bool use_callers_arena);
|
||||
bool
|
||||
sp_eval_expr(THD *thd, Field *result_field, Item *expr_item);
|
||||
|
||||
#endif /* _SP_HEAD_H_ */
|
||||
|
|
|
@ -51,21 +51,26 @@ sp_cond_check(LEX_STRING *sqlstate)
|
|||
}
|
||||
|
||||
sp_pcontext::sp_pcontext(sp_pcontext *prev)
|
||||
: Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
|
||||
m_handlers(0), m_parent(prev), m_pboundary(0)
|
||||
:Sql_alloc(), m_total_pvars(0), m_csubsize(0), m_hsubsize(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_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_cursor, sizeof(LEX_STRING), 16, 8));
|
||||
VOID(my_init_dynamic_array(&m_handler, sizeof(sp_cond_type_t *), 16, 8));
|
||||
m_label.empty();
|
||||
m_children.empty();
|
||||
if (!prev)
|
||||
{
|
||||
m_poffset= m_coffset= 0;
|
||||
m_num_case_exprs= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_poffset= prev->current_pvars();
|
||||
m_poffset= prev->m_poffset + prev->m_total_pvars;
|
||||
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_label.empty();
|
||||
delete_dynamic(&m_pvar);
|
||||
delete_dynamic(&m_case_expr_id_lst);
|
||||
delete_dynamic(&m_cond);
|
||||
delete_dynamic(&m_cursor);
|
||||
delete_dynamic(&m_handler);
|
||||
|
@ -99,16 +105,19 @@ sp_pcontext::push_context()
|
|||
sp_pcontext *
|
||||
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)
|
||||
m_parent->m_psubsize= submax;
|
||||
submax= max_handlers();
|
||||
uint submax= max_handlers();
|
||||
if (submax > m_parent->m_hsubsize)
|
||||
m_parent->m_hsubsize= submax;
|
||||
|
||||
submax= max_cursors();
|
||||
if (submax > m_parent->m_csubsize)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -191,26 +200,29 @@ sp_pcontext::find_pvar(uint offset)
|
|||
return NULL; // index out of bounds
|
||||
}
|
||||
|
||||
void
|
||||
sp_pvar_t *
|
||||
sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type,
|
||||
sp_param_mode_t mode)
|
||||
{
|
||||
sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
|
||||
|
||||
if (p)
|
||||
{
|
||||
if (m_pvar.elements == m_psubsize)
|
||||
m_psubsize+= 1;
|
||||
p->name.str= name->str;
|
||||
p->name.length= name->length;
|
||||
p->type= type;
|
||||
p->mode= mode;
|
||||
p->offset= current_pvars();
|
||||
p->dflt= NULL;
|
||||
insert_dynamic(&m_pvar, (gptr)&p);
|
||||
}
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
++m_total_pvars;
|
||||
|
||||
p->name.str= name->str;
|
||||
p->name.length= name->length;
|
||||
p->type= type;
|
||||
p->mode= mode;
|
||||
p->offset= current_pvars();
|
||||
p->dflt= NULL;
|
||||
insert_dynamic(&m_pvar, (gptr)&p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
sp_label_t *
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
This is only used for debugging.
|
||||
|
|
|
@ -34,8 +34,16 @@ typedef struct sp_pvar
|
|||
LEX_STRING name;
|
||||
enum enum_field_types type;
|
||||
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;
|
||||
create_field field_def;
|
||||
} sp_pvar_t;
|
||||
|
||||
|
||||
|
@ -114,9 +122,9 @@ class sp_pcontext : public Sql_alloc
|
|||
//
|
||||
|
||||
inline uint
|
||||
max_pvars()
|
||||
total_pvars()
|
||||
{
|
||||
return m_psubsize + m_pvar.elements;
|
||||
return m_total_pvars;
|
||||
}
|
||||
|
||||
inline uint
|
||||
|
@ -155,16 +163,15 @@ class sp_pcontext : public Sql_alloc
|
|||
p->dflt= it;
|
||||
}
|
||||
|
||||
void
|
||||
sp_pvar_t *
|
||||
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
|
||||
pop_pvar(uint num = 1)
|
||||
{
|
||||
while (num--)
|
||||
pop_dynamic(&m_pvar);
|
||||
}
|
||||
/*
|
||||
Retrieve definitions of fields from the current context and its
|
||||
children.
|
||||
*/
|
||||
void
|
||||
retrieve_field_definitions(List<create_field> *field_def_lst);
|
||||
|
||||
// Find by name
|
||||
sp_pvar_t *
|
||||
|
@ -175,7 +182,7 @@ class sp_pcontext : public Sql_alloc
|
|||
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.
|
||||
*/
|
||||
inline void
|
||||
|
@ -184,6 +191,45 @@ class sp_pcontext : public Sql_alloc
|
|||
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
|
||||
//
|
||||
|
@ -280,8 +326,18 @@ class sp_pcontext : public Sql_alloc
|
|||
|
||||
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
|
||||
uint m_psubsize;
|
||||
uint m_csubsize;
|
||||
uint m_hsubsize;
|
||||
uint m_handlers; // No. of handlers in this context
|
||||
|
@ -290,8 +346,19 @@ private:
|
|||
|
||||
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
|
||||
|
||||
/*
|
||||
Boundary for finding variables in this context. This is the number
|
||||
of variables currently "invisible" to default clauses.
|
||||
|
@ -300,7 +367,10 @@ private:
|
|||
*/
|
||||
uint m_pboundary;
|
||||
|
||||
int m_num_case_exprs;
|
||||
|
||||
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_cursor; // Cursors
|
||||
DYNAMIC_ARRAY m_handler; // Handlers, for checking of duplicates
|
||||
|
|
|
@ -29,41 +29,137 @@
|
|||
#include "sp_rcontext.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),
|
||||
m_ihsp(0), m_hfound(-1), m_ccount(0), m_prev_ctx(prev)
|
||||
|
||||
sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
|
||||
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::set_item_eval(THD *thd, uint idx, Item **item_addr,
|
||||
enum_field_types type)
|
||||
sp_rcontext::~sp_rcontext()
|
||||
{
|
||||
Item *it;
|
||||
Item *reuse_it;
|
||||
/* sp_eval_func_item will use callers_arena */
|
||||
int res;
|
||||
if (m_var_table)
|
||||
free_blobs(m_var_table);
|
||||
}
|
||||
|
||||
reuse_it= get_item(idx);
|
||||
it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE);
|
||||
if (! it)
|
||||
res= -1;
|
||||
else
|
||||
|
||||
/*
|
||||
Initialize sp_rcontext instance.
|
||||
|
||||
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;
|
||||
set_item(idx, it);
|
||||
if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx])))
|
||||
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
|
||||
sp_rcontext::find_handler(uint sql_errno,
|
||||
MYSQL_ERROR::enum_warning_level level)
|
||||
|
@ -117,32 +213,14 @@ sp_rcontext::find_handler(uint sql_errno,
|
|||
}
|
||||
if (found < 0)
|
||||
{
|
||||
if (m_prev_ctx)
|
||||
return m_prev_ctx->find_handler(sql_errno, level);
|
||||
if (m_prev_runtime_ctx)
|
||||
return m_prev_runtime_ctx->find_handler(sql_errno, level);
|
||||
return FALSE;
|
||||
}
|
||||
m_hfound= found;
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
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
|
||||
|
@ -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
|
||||
****************************************************************************/
|
||||
|
@ -294,11 +503,8 @@ bool Select_fetch_into_spvars::send_data(List<Item> &items)
|
|||
*/
|
||||
for (; pv= pv_iter++, item= item_iter++; )
|
||||
{
|
||||
Item *reuse= thd->spcont->get_item(pv->offset);
|
||||
/* Evaluate a new item on the arena of the calling instruction */
|
||||
Item *it= sp_eval_func_item(thd, &item, pv->type, reuse, TRUE);
|
||||
|
||||
thd->spcont->set_item(pv->offset, it);
|
||||
if (thd->spcont->set_variable(thd, pv->offset, item))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -43,12 +43,22 @@ typedef struct
|
|||
|
||||
|
||||
/*
|
||||
This is a run context? of one SP ?
|
||||
THis is
|
||||
- a stack of cursors?
|
||||
- a stack of handlers?
|
||||
- a stack of Items ?
|
||||
- a stack of instruction locations in SP?
|
||||
This class is a runtime context of a Stored Routine. It is used in an
|
||||
execution and is intended to contain all dynamic objects (i.e. objects, which
|
||||
can be changed during execution), such as:
|
||||
- stored routine variables;
|
||||
- cursors;
|
||||
- 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
|
||||
|
@ -68,62 +78,34 @@ class sp_rcontext : public Sql_alloc
|
|||
|
||||
#ifndef DBUG_OFF
|
||||
/*
|
||||
Routine to which this Item_splocal belongs. Used for checking if correct
|
||||
runtime context is used for variable handling.
|
||||
The routine for which this runtime context is created. Used for checking
|
||||
if correct runtime context is used for variable handling.
|
||||
*/
|
||||
sp_head *owner;
|
||||
sp_head *sp;
|
||||
#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()
|
||||
{
|
||||
// Not needed?
|
||||
//sql_element_free(m_frame);
|
||||
//m_saved.empty();
|
||||
}
|
||||
~sp_rcontext();
|
||||
|
||||
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
|
||||
set_item_eval(THD *thd, uint idx, Item **i, enum_field_types type);
|
||||
set_variable(THD *thd, uint var_idx, Item *value);
|
||||
|
||||
inline Item *
|
||||
get_item(uint idx)
|
||||
Item *
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
return m_return_value_set;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -195,14 +177,6 @@ class sp_rcontext : public Sql_alloc
|
|||
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
|
||||
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];
|
||||
}
|
||||
|
||||
/*
|
||||
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:
|
||||
sp_pcontext *m_root_parsing_ctx;
|
||||
|
||||
uint m_count;
|
||||
uint m_fsize;
|
||||
Item **m_frame;
|
||||
/* Virtual table for storing variables. */
|
||||
TABLE *m_var_table;
|
||||
|
||||
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
|
||||
uint m_hcount; // Stack pointer for m_handler
|
||||
|
@ -236,13 +239,22 @@ private:
|
|||
uint *m_in_handler; // Active handler, for recursion check
|
||||
uint m_ihsp; // Stack pointer for m_in_handler
|
||||
int m_hfound; // Set by find_handler; -1 if not found
|
||||
List<Item> m_saved; // Saved variables during handler exec.
|
||||
|
||||
sp_cursor **m_cstack;
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -1503,10 +1503,10 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
|||
my_var *mv= gl++;
|
||||
if (mv->local)
|
||||
{
|
||||
Item_splocal *var;
|
||||
(void)local_vars.push_back(var= new Item_splocal(mv->s, mv->offset));
|
||||
Item_splocal *var= new Item_splocal(mv->s, mv->offset, mv->type);
|
||||
(void)local_vars.push_back(var);
|
||||
#ifndef DBUG_OFF
|
||||
var->owner= mv->owner;
|
||||
var->m_sp= mv->sp;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -1779,8 +1779,8 @@ bool select_dumpvar::send_data(List<Item> &items)
|
|||
{
|
||||
if ((yy=var_li++))
|
||||
{
|
||||
if (thd->spcont->set_item_eval(current_thd,
|
||||
yy->get_offset(), it.ref(), zz->type))
|
||||
if (thd->spcont->set_variable(current_thd, yy->get_var_idx(),
|
||||
*it.ref()))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2100,7 +2100,7 @@ public:
|
|||
Routine to which this Item_splocal belongs. Used for checking if correct
|
||||
runtime context is used for variable handling.
|
||||
*/
|
||||
sp_head *owner;
|
||||
sp_head *sp;
|
||||
#endif
|
||||
bool local;
|
||||
uint offset;
|
||||
|
|
341
sql/sql_parse.cc
341
sql/sql_parse.cc
|
@ -2617,7 +2617,8 @@ mysql_execute_command(THD *thd)
|
|||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res = mysql_backup_table(thd, first_table);
|
||||
|
||||
select_lex->table_list.first= (byte*) first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_RESTORE_TABLE:
|
||||
|
@ -2629,6 +2630,8 @@ mysql_execute_command(THD *thd)
|
|||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res = mysql_restore_table(thd, first_table);
|
||||
select_lex->table_list.first= (byte*) first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_ASSIGN_TO_KEYCACHE:
|
||||
|
@ -3131,6 +3134,8 @@ end_with_restore_list:
|
|||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
}
|
||||
select_lex->table_list.first= (byte*) first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_CHECK:
|
||||
|
@ -3141,6 +3146,8 @@ end_with_restore_list:
|
|||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res = mysql_check_table(thd, first_table, &lex->check_opt);
|
||||
select_lex->table_list.first= (byte*) first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_ANALYZE:
|
||||
|
@ -3161,6 +3168,8 @@ end_with_restore_list:
|
|||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
}
|
||||
select_lex->table_list.first= (byte*) first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3184,6 +3193,8 @@ end_with_restore_list:
|
|||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
}
|
||||
select_lex->table_list.first= (byte*) first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_UPDATE:
|
||||
|
@ -5759,9 +5770,10 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
|||
buf, "TIMESTAMP");
|
||||
}
|
||||
|
||||
if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
|
||||
type_modifier, default_value, on_update_value,
|
||||
comment, change, interval_list, cs, uint_geom_type)))
|
||||
if (!(new_field= new create_field()) ||
|
||||
new_field->init(thd, field_name, type, length, decimals, type_modifier,
|
||||
default_value, on_update_value, comment, change,
|
||||
interval_list, cs, uint_geom_type))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
lex->create_list.push_back(new_field);
|
||||
|
@ -5769,327 +5781,6 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
|||
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 */
|
||||
|
||||
|
|
|
@ -8911,6 +8911,7 @@ err:
|
|||
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
|
||||
{
|
||||
uint field_count= field_list.elements;
|
||||
uint blob_count= 0;
|
||||
Field **field;
|
||||
create_field *cdef; /* column definition */
|
||||
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;
|
||||
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 */
|
||||
List_iterator_fast<create_field> it(field_list);
|
||||
while ((cdef= it++))
|
||||
|
@ -8942,9 +8949,15 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
|
|||
record_length+= (**field).pack_length();
|
||||
if (! ((**field).flags & NOT_NULL_FLAG))
|
||||
++null_count;
|
||||
|
||||
if ((*field)->flags & BLOB_FLAG)
|
||||
s->blob_field[blob_count++]= (uint) (field - table->field);
|
||||
|
||||
++field;
|
||||
}
|
||||
*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;
|
||||
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,
|
||||
ulonglong select_options, ha_rows rows_limit,
|
||||
char* alias);
|
||||
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
|
||||
void free_tmp_table(THD *thd, TABLE *entry);
|
||||
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
|
||||
bool reset_with_sum_func);
|
||||
|
|
|
@ -2222,18 +2222,14 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||
*/
|
||||
lex->query_tables= table;
|
||||
lex->query_tables_last= &table->next_global;
|
||||
lex->query_tables_own_last= 0;;
|
||||
lex->query_tables_own_last= 0;
|
||||
thd->no_warnings_for_error= no_warnings_for_error;
|
||||
if (view_operator_func == NULL)
|
||||
table->required_type=FRMTYPE_TABLE;
|
||||
open_and_lock_tables(thd, table);
|
||||
thd->no_warnings_for_error= 0;
|
||||
table->next_global= save_next_global;
|
||||
table->next_local= save_next_local;
|
||||
/* if view are unsupported */
|
||||
if (table->view && view_operator_func == NULL)
|
||||
{
|
||||
result_code= HA_ADMIN_NOT_BASE_TABLE;
|
||||
goto send_result;
|
||||
}
|
||||
thd->open_options&= ~extra_open_options;
|
||||
|
||||
if (prepare_func)
|
||||
|
|
|
@ -1123,7 +1123,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
|||
trg_action_time_type time_type,
|
||||
bool old_row_is_record1)
|
||||
{
|
||||
int res= 0;
|
||||
bool err_status= FALSE;
|
||||
sp_head *sp_trigger= bodies[event][time_type];
|
||||
|
||||
if (sp_trigger)
|
||||
|
@ -1183,7 +1183,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
|||
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
||||
|
||||
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);
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
return res;
|
||||
return err_status;
|
||||
}
|
||||
|
||||
|
||||
|
|
232
sql/sql_yacc.yy
232
sql/sql_yacc.yy
|
@ -1350,41 +1350,11 @@ create_function_tail:
|
|||
{
|
||||
LEX *lex= Lex;
|
||||
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*) "",
|
||||
(enum enum_field_types)$8,
|
||||
lex->length, lex->dec, lex->type,
|
||||
(Item *)0, (Item *) 0, &cmt, 0,
|
||||
&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;
|
||||
if (sp->fill_field_definition(YYTHD, lex,
|
||||
(enum enum_field_types) $8,
|
||||
&sp->m_return_field_def))
|
||||
YYABORT;
|
||||
|
||||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||||
}
|
||||
|
@ -1506,8 +1476,28 @@ sp_fdparams:
|
|||
| 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:
|
||||
ident type
|
||||
ident sp_init_param type
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
|
@ -1517,7 +1507,17 @@ sp_fdparam:
|
|||
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
|
||||
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_opt_inout ident type
|
||||
sp_opt_inout sp_init_param ident type
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
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;
|
||||
}
|
||||
spc->push_pvar(&$2, (enum enum_field_types)$3,
|
||||
(sp_param_mode_t)$1);
|
||||
sp_pvar_t *pvar= spc->push_pvar(&$3, (enum enum_field_types)$4,
|
||||
(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:
|
||||
DECLARE_SYM sp_decl_idents type
|
||||
DECLARE_SYM sp_decl_idents
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
|
||||
lex->sphead->reset_lex(YYTHD);
|
||||
lex->spcont->declare_var_boundary($2);
|
||||
}
|
||||
type
|
||||
sp_opt_default
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
sp_pcontext *ctx= lex->spcont;
|
||||
uint max= ctx->context_pvars();
|
||||
enum enum_field_types type= (enum enum_field_types)$3;
|
||||
Item *it= $5;
|
||||
bool has_default= (it != NULL);
|
||||
|
||||
for (uint i = max-$2 ; i < max ; i++)
|
||||
sp_pcontext *pctx= lex->spcont;
|
||||
uint num_vars= pctx->context_pvars();
|
||||
enum enum_field_types var_type= (enum enum_field_types) $4;
|
||||
Item *dflt_value_item= $5;
|
||||
create_field *create_field_op;
|
||||
|
||||
if (!dflt_value_item)
|
||||
{
|
||||
sp_instr_set *in;
|
||||
uint off= ctx->pvar_context2index(i);
|
||||
|
||||
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);
|
||||
dflt_value_item= new Item_null();
|
||||
/* QQ Set to the var_type with null_value? */
|
||||
}
|
||||
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);
|
||||
|
||||
$$.vars= $2;
|
||||
$$.conds= $$.hndlrs= $$.curs= 0;
|
||||
}
|
||||
|
@ -1857,6 +1881,8 @@ sp_hcond:
|
|||
sp_decl_idents:
|
||||
ident
|
||||
{
|
||||
/* NOTE: field definition is filled in sp_decl section. */
|
||||
|
||||
LEX *lex= Lex;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
|
||||
|
@ -1870,6 +1896,8 @@ sp_decl_idents:
|
|||
}
|
||||
| sp_decl_idents ',' ident
|
||||
{
|
||||
/* NOTE: field definition is filled in sp_decl section. */
|
||||
|
||||
LEX *lex= Lex;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
|
||||
|
@ -1947,8 +1975,8 @@ sp_proc_stmt:
|
|||
{
|
||||
sp_instr_freturn *i;
|
||||
|
||||
i= new sp_instr_freturn(sp->instructions(), lex->spcont,
|
||||
$3, sp->m_returns, lex);
|
||||
i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3,
|
||||
sp->m_return_field_def.sql_type, lex);
|
||||
sp->add_instr(i);
|
||||
sp->m_flags|= sp_head::HAS_RETURN;
|
||||
}
|
||||
|
@ -1964,25 +1992,27 @@ sp_proc_stmt:
|
|||
{ Lex->sphead->reset_lex(YYTHD); }
|
||||
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;
|
||||
uint offset= lex->spcont->current_pvars();
|
||||
sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
|
||||
lex->spcont, offset, $3,
|
||||
MYSQL_TYPE_STRING, lex, TRUE);
|
||||
LEX_STRING dummy={(char*)"", 0};
|
||||
|
||||
lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
|
||||
lex->sphead->add_instr(i);
|
||||
lex->sphead->m_flags|= sp_head::IN_SIMPLE_CASE;
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
sp_head *sp= lex->sphead;
|
||||
sp_pcontext *parsing_ctx= lex->spcont;
|
||||
int case_expr_id= parsing_ctx->register_case_expr();
|
||||
|
||||
if (parsing_ctx->push_case_expr_id(case_expr_id))
|
||||
YYABORT;
|
||||
|
||||
sp->add_instr(
|
||||
new sp_instr_set_case_expr(sp->instructions(),
|
||||
parsing_ctx,
|
||||
case_expr_id,
|
||||
$3,
|
||||
lex));
|
||||
|
||||
sp->m_flags|= sp_head::IN_SIMPLE_CASE;
|
||||
sp->restore_lex(YYTHD);
|
||||
}
|
||||
sp_case END CASE_SYM
|
||||
{
|
||||
Lex->spcont->pop_pvar();
|
||||
Lex->spcont->pop_case_expr_id();
|
||||
}
|
||||
| sp_labeled_control
|
||||
{}
|
||||
|
@ -2293,20 +2323,20 @@ sp_case:
|
|||
i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
|
||||
else
|
||||
{ /* Simple case: <caseval> = <whenval> */
|
||||
LEX_STRING ivar;
|
||||
|
||||
ivar.str= (char *)"_tmp_";
|
||||
ivar.length= 5;
|
||||
Item_splocal *var= new Item_splocal(ivar,
|
||||
ctx->current_pvars()-1);
|
||||
Item_case_expr *var;
|
||||
Item *expr;
|
||||
|
||||
var= new Item_case_expr(ctx->get_current_case_expr_id());
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
if (var)
|
||||
var->owner= sp;
|
||||
var->m_sp= sp;
|
||||
#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);
|
||||
lex->variables_used= 1;
|
||||
}
|
||||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||||
sp->add_instr(i);
|
||||
|
@ -3783,11 +3813,6 @@ optimize:
|
|||
OPTIMIZE opt_no_write_to_binlog table_or_tables
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
if (lex->sphead)
|
||||
{
|
||||
my_error(ER_SP_BADSTATEMENT, MYF(0), "OPTIMIZE TABLE");
|
||||
YYABORT;
|
||||
}
|
||||
lex->sql_command = SQLCOM_OPTIMIZE;
|
||||
lex->no_write_to_binlog= $2;
|
||||
lex->check_opt.init();
|
||||
|
@ -4406,11 +4431,9 @@ simple_expr:
|
|||
{
|
||||
if ($3->is_splocal())
|
||||
{
|
||||
LEX_STRING *name;
|
||||
Item_splocal *il= static_cast<Item_splocal *>($3);
|
||||
|
||||
name= il->my_name(NULL);
|
||||
my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str);
|
||||
my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
|
||||
YYABORT;
|
||||
}
|
||||
$$= new Item_default_value(Lex->current_context(), $3);
|
||||
|
@ -5878,7 +5901,7 @@ select_var_ident:
|
|||
var_list.push_back(var= new my_var($1,1,t->offset,t->type));
|
||||
#ifndef DBUG_OFF
|
||||
if (var)
|
||||
var->owner= lex->sphead;
|
||||
var->sp= lex->sphead;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -7180,11 +7203,12 @@ simple_ident:
|
|||
{
|
||||
/* We're compiling a stored procedure and found a variable */
|
||||
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);
|
||||
#ifndef DBUG_OFF
|
||||
if (splocal)
|
||||
splocal->owner= lex->sphead;
|
||||
splocal->m_sp= lex->sphead;
|
||||
#endif
|
||||
$$ = (Item*) splocal;
|
||||
lex->variables_used= 1;
|
||||
|
|
Loading…
Reference in a new issue