mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 05:22:25 +01:00
Automerge of mysql-5.1-bugteam into mysql-trunk-merge.
This commit is contained in:
commit
084ffd12a3
36 changed files with 1680 additions and 624 deletions
|
@ -4335,7 +4335,7 @@ com_status(String *buffer __attribute__((unused)),
|
|||
Don't remove "limit 1",
|
||||
it is protection againts SQL_SELECT_LIMIT=0
|
||||
*/
|
||||
if (mysql_store_result_for_lazy(&result))
|
||||
if (!mysql_store_result_for_lazy(&result))
|
||||
{
|
||||
MYSQL_ROW cur=mysql_fetch_row(result);
|
||||
if (cur)
|
||||
|
@ -4379,7 +4379,7 @@ com_status(String *buffer __attribute__((unused)),
|
|||
if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR)
|
||||
return 0;
|
||||
}
|
||||
if (mysql_store_result_for_lazy(&result))
|
||||
if (!mysql_store_result_for_lazy(&result))
|
||||
{
|
||||
MYSQL_ROW cur=mysql_fetch_row(result);
|
||||
if (cur)
|
||||
|
@ -4474,9 +4474,7 @@ server_version_string(MYSQL *con)
|
|||
*/
|
||||
|
||||
if (server_version == NULL)
|
||||
{
|
||||
server_version= strdup(mysql_get_server_info(con));
|
||||
}
|
||||
server_version= my_strdup(mysql_get_server_info(con), MYF(MY_WME));
|
||||
}
|
||||
|
||||
return server_version ? server_version : "";
|
||||
|
|
|
@ -557,16 +557,6 @@ unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql,
|
|||
char *to,const char *from,
|
||||
unsigned long length);
|
||||
void STDCALL mysql_debug(const char *debug);
|
||||
char * STDCALL mysql_odbc_escape_string(MYSQL *mysql,
|
||||
char *to,
|
||||
unsigned long to_length,
|
||||
const char *from,
|
||||
unsigned long from_length,
|
||||
void *param,
|
||||
char *
|
||||
(*extend_buffer)
|
||||
(void *, char *to,
|
||||
unsigned long *length));
|
||||
void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name);
|
||||
unsigned int STDCALL mysql_thread_safe(void);
|
||||
my_bool STDCALL mysql_embedded(void);
|
||||
|
|
|
@ -518,16 +518,6 @@ unsigned long mysql_real_escape_string(MYSQL *mysql,
|
|||
char *to,const char *from,
|
||||
unsigned long length);
|
||||
void mysql_debug(const char *debug);
|
||||
char * mysql_odbc_escape_string(MYSQL *mysql,
|
||||
char *to,
|
||||
unsigned long to_length,
|
||||
const char *from,
|
||||
unsigned long from_length,
|
||||
void *param,
|
||||
char *
|
||||
(*extend_buffer)
|
||||
(void *, char *to,
|
||||
unsigned long *length));
|
||||
void myodbc_remove_escape(MYSQL *mysql,char *name);
|
||||
unsigned int mysql_thread_safe(void);
|
||||
my_bool mysql_embedded(void);
|
||||
|
|
|
@ -1629,20 +1629,6 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
|
|||
return (uint) escape_string_for_mysql(mysql->charset, to, 0, from, length);
|
||||
}
|
||||
|
||||
|
||||
char * STDCALL
|
||||
mysql_odbc_escape_string(MYSQL *mysql __attribute__((unused)),
|
||||
char *to __attribute__((unused)),
|
||||
ulong to_length __attribute__((unused)),
|
||||
const char *from __attribute__((unused)),
|
||||
ulong from_length __attribute__((unused)),
|
||||
void *param __attribute__((unused)),
|
||||
char * (*extend_buffer)(void *, char *, ulong *)
|
||||
__attribute__((unused)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void STDCALL
|
||||
myodbc_remove_escape(MYSQL *mysql,char *name)
|
||||
{
|
||||
|
|
|
@ -78,7 +78,6 @@ EXPORTS
|
|||
mysql_next_result
|
||||
mysql_num_fields
|
||||
mysql_num_rows
|
||||
mysql_odbc_escape_string
|
||||
mysql_options
|
||||
mysql_stmt_param_count
|
||||
mysql_stmt_param_metadata
|
||||
|
|
|
@ -50,7 +50,6 @@ EXPORTS
|
|||
mysql_next_result
|
||||
mysql_num_fields
|
||||
mysql_num_rows
|
||||
mysql_odbc_escape_string
|
||||
mysql_options
|
||||
mysql_ping
|
||||
mysql_query
|
||||
|
|
13
mysql-test/r/bug47671.result
Normal file
13
mysql-test/r/bug47671.result
Normal file
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Bug#47671 - wrong character-set after upgrade from 5.1.34 to 5.1.39
|
||||
#
|
||||
# Extract only charset information from 'status' command output using regex
|
||||
--------------
|
||||
|
||||
Server characterset: utf8
|
||||
Db characterset: utf8
|
||||
Client characterset: utf8
|
||||
Conn. characterset: utf8
|
||||
|
||||
--------------
|
||||
|
|
@ -885,7 +885,7 @@ cast(sum(distinct df) as signed)
|
|||
3
|
||||
select cast(min(df) as signed) from t1;
|
||||
cast(min(df) as signed)
|
||||
0
|
||||
1
|
||||
select 1e8 * sum(distinct df) from t1;
|
||||
1e8 * sum(distinct df)
|
||||
330000000
|
||||
|
@ -1520,4 +1520,197 @@ max i
|
|||
# Cleanup
|
||||
#
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug#43668: Wrong comparison and MIN/MAX for YEAR(2)
|
||||
#
|
||||
create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime);
|
||||
insert into t1 values
|
||||
(98,1998,19980101,"1998-01-01 00:00:00"),
|
||||
(00,2000,20000101,"2000-01-01 00:00:01"),
|
||||
(02,2002,20020101,"2002-01-01 23:59:59"),
|
||||
(60,2060,20600101,"2060-01-01 11:11:11"),
|
||||
(70,1970,19700101,"1970-11-11 22:22:22"),
|
||||
(NULL,NULL,NULL,NULL);
|
||||
select min(f1),max(f1) from t1;
|
||||
min(f1) max(f1)
|
||||
70 60
|
||||
select min(f2),max(f2) from t1;
|
||||
min(f2) max(f2)
|
||||
1970 2060
|
||||
select min(f3),max(f3) from t1;
|
||||
min(f3) max(f3)
|
||||
1970-01-01 2060-01-01
|
||||
select min(f4),max(f4) from t1;
|
||||
min(f4) max(f4)
|
||||
1970-11-11 22:22:22 2060-01-01 11:11:11
|
||||
select a.f1 as a, b.f1 as b, a.f1 > b.f1 as gt,
|
||||
a.f1 < b.f1 as lt, a.f1<=>b.f1 as eq
|
||||
from t1 a, t1 b;
|
||||
a b gt lt eq
|
||||
98 98 0 0 1
|
||||
00 98 1 0 0
|
||||
02 98 1 0 0
|
||||
60 98 1 0 0
|
||||
70 98 0 1 0
|
||||
NULL 98 NULL NULL 0
|
||||
98 00 0 1 0
|
||||
00 00 0 0 1
|
||||
02 00 1 0 0
|
||||
60 00 1 0 0
|
||||
70 00 0 1 0
|
||||
NULL 00 NULL NULL 0
|
||||
98 02 0 1 0
|
||||
00 02 0 1 0
|
||||
02 02 0 0 1
|
||||
60 02 1 0 0
|
||||
70 02 0 1 0
|
||||
NULL 02 NULL NULL 0
|
||||
98 60 0 1 0
|
||||
00 60 0 1 0
|
||||
02 60 0 1 0
|
||||
60 60 0 0 1
|
||||
70 60 0 1 0
|
||||
NULL 60 NULL NULL 0
|
||||
98 70 1 0 0
|
||||
00 70 1 0 0
|
||||
02 70 1 0 0
|
||||
60 70 1 0 0
|
||||
70 70 0 0 1
|
||||
NULL 70 NULL NULL 0
|
||||
98 NULL NULL NULL 0
|
||||
00 NULL NULL NULL 0
|
||||
02 NULL NULL NULL 0
|
||||
60 NULL NULL NULL 0
|
||||
70 NULL NULL NULL 0
|
||||
NULL NULL NULL NULL 1
|
||||
select a.f1 as a, b.f2 as b, a.f1 > b.f2 as gt,
|
||||
a.f1 < b.f2 as lt, a.f1<=>b.f2 as eq
|
||||
from t1 a, t1 b;
|
||||
a b gt lt eq
|
||||
98 1998 0 0 1
|
||||
00 1998 1 0 0
|
||||
02 1998 1 0 0
|
||||
60 1998 1 0 0
|
||||
70 1998 0 1 0
|
||||
NULL 1998 NULL NULL 0
|
||||
98 2000 0 1 0
|
||||
00 2000 0 0 1
|
||||
02 2000 1 0 0
|
||||
60 2000 1 0 0
|
||||
70 2000 0 1 0
|
||||
NULL 2000 NULL NULL 0
|
||||
98 2002 0 1 0
|
||||
00 2002 0 1 0
|
||||
02 2002 0 0 1
|
||||
60 2002 1 0 0
|
||||
70 2002 0 1 0
|
||||
NULL 2002 NULL NULL 0
|
||||
98 2060 0 1 0
|
||||
00 2060 0 1 0
|
||||
02 2060 0 1 0
|
||||
60 2060 0 0 1
|
||||
70 2060 0 1 0
|
||||
NULL 2060 NULL NULL 0
|
||||
98 1970 1 0 0
|
||||
00 1970 1 0 0
|
||||
02 1970 1 0 0
|
||||
60 1970 1 0 0
|
||||
70 1970 0 0 1
|
||||
NULL 1970 NULL NULL 0
|
||||
98 NULL NULL NULL 0
|
||||
00 NULL NULL NULL 0
|
||||
02 NULL NULL NULL 0
|
||||
60 NULL NULL NULL 0
|
||||
70 NULL NULL NULL 0
|
||||
NULL NULL NULL NULL 1
|
||||
select a.f1 as a, b.f3 as b, a.f1 > b.f3 as gt,
|
||||
a.f1 < b.f3 as lt, a.f1<=>b.f3 as eq
|
||||
from t1 a, t1 b;
|
||||
a b gt lt eq
|
||||
98 1998-01-01 0 1 0
|
||||
00 1998-01-01 1 0 0
|
||||
02 1998-01-01 1 0 0
|
||||
60 1998-01-01 1 0 0
|
||||
70 1998-01-01 0 1 0
|
||||
NULL 1998-01-01 NULL NULL 0
|
||||
98 2000-01-01 0 1 0
|
||||
00 2000-01-01 0 1 0
|
||||
02 2000-01-01 1 0 0
|
||||
60 2000-01-01 1 0 0
|
||||
70 2000-01-01 0 1 0
|
||||
NULL 2000-01-01 NULL NULL 0
|
||||
98 2002-01-01 0 1 0
|
||||
00 2002-01-01 0 1 0
|
||||
02 2002-01-01 0 1 0
|
||||
60 2002-01-01 1 0 0
|
||||
70 2002-01-01 0 1 0
|
||||
NULL 2002-01-01 NULL NULL 0
|
||||
98 2060-01-01 0 1 0
|
||||
00 2060-01-01 0 1 0
|
||||
02 2060-01-01 0 1 0
|
||||
60 2060-01-01 0 1 0
|
||||
70 2060-01-01 0 1 0
|
||||
NULL 2060-01-01 NULL NULL 0
|
||||
98 1970-01-01 1 0 0
|
||||
00 1970-01-01 1 0 0
|
||||
02 1970-01-01 1 0 0
|
||||
60 1970-01-01 1 0 0
|
||||
70 1970-01-01 0 1 0
|
||||
NULL 1970-01-01 NULL NULL 0
|
||||
98 NULL NULL NULL 0
|
||||
00 NULL NULL NULL 0
|
||||
02 NULL NULL NULL 0
|
||||
60 NULL NULL NULL 0
|
||||
70 NULL NULL NULL 0
|
||||
NULL NULL NULL NULL 1
|
||||
select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt,
|
||||
a.f1 < b.f4 as lt, a.f1<=>b.f4 as eq
|
||||
from t1 a, t1 b;
|
||||
a b gt lt eq
|
||||
98 1998-01-01 00:00:00 0 1 0
|
||||
00 1998-01-01 00:00:00 1 0 0
|
||||
02 1998-01-01 00:00:00 1 0 0
|
||||
60 1998-01-01 00:00:00 1 0 0
|
||||
70 1998-01-01 00:00:00 0 1 0
|
||||
NULL 1998-01-01 00:00:00 NULL NULL 0
|
||||
98 2000-01-01 00:00:01 0 1 0
|
||||
00 2000-01-01 00:00:01 0 1 0
|
||||
02 2000-01-01 00:00:01 1 0 0
|
||||
60 2000-01-01 00:00:01 1 0 0
|
||||
70 2000-01-01 00:00:01 0 1 0
|
||||
NULL 2000-01-01 00:00:01 NULL NULL 0
|
||||
98 2002-01-01 23:59:59 0 1 0
|
||||
00 2002-01-01 23:59:59 0 1 0
|
||||
02 2002-01-01 23:59:59 0 1 0
|
||||
60 2002-01-01 23:59:59 1 0 0
|
||||
70 2002-01-01 23:59:59 0 1 0
|
||||
NULL 2002-01-01 23:59:59 NULL NULL 0
|
||||
98 2060-01-01 11:11:11 0 1 0
|
||||
00 2060-01-01 11:11:11 0 1 0
|
||||
02 2060-01-01 11:11:11 0 1 0
|
||||
60 2060-01-01 11:11:11 0 1 0
|
||||
70 2060-01-01 11:11:11 0 1 0
|
||||
NULL 2060-01-01 11:11:11 NULL NULL 0
|
||||
98 1970-11-11 22:22:22 1 0 0
|
||||
00 1970-11-11 22:22:22 1 0 0
|
||||
02 1970-11-11 22:22:22 1 0 0
|
||||
60 1970-11-11 22:22:22 1 0 0
|
||||
70 1970-11-11 22:22:22 0 1 0
|
||||
NULL 1970-11-11 22:22:22 NULL NULL 0
|
||||
98 NULL NULL NULL 0
|
||||
00 NULL NULL NULL 0
|
||||
02 NULL NULL NULL 0
|
||||
60 NULL NULL NULL 0
|
||||
70 NULL NULL NULL 0
|
||||
NULL NULL NULL NULL 1
|
||||
select *, f1 = f2 from t1;
|
||||
f1 f2 f3 f4 f1 = f2
|
||||
98 1998 1998-01-01 1998-01-01 00:00:00 1
|
||||
00 2000 2000-01-01 2000-01-01 00:00:01 1
|
||||
02 2002 2002-01-01 2002-01-01 23:59:59 1
|
||||
60 2060 2060-01-01 2060-01-01 11:11:11 1
|
||||
70 1970 1970-01-01 1970-11-11 22:22:22 1
|
||||
NULL NULL NULL NULL NULL
|
||||
drop table t1;
|
||||
#
|
||||
End of 5.1 tests
|
||||
|
|
|
@ -443,3 +443,30 @@ DROP TABLE db1.t1, db1.t2;
|
|||
DROP USER mysqltest1@localhost;
|
||||
DROP DATABASE db1;
|
||||
End of 5.0 tests
|
||||
USE mysql;
|
||||
SELECT LEFT(CURRENT_USER(),INSTR(CURRENT_USER(),'@')-1) INTO @u;
|
||||
SELECT MID(CURRENT_USER(),INSTR(CURRENT_USER(),'@')+1) INTO @h;
|
||||
SELECT password FROM user WHERE user=@u AND host=@h INTO @pwd;
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
user host password insert_priv
|
||||
root localhost Y
|
||||
UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h;
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
user host password insert_priv
|
||||
root localhost N
|
||||
GRANT INSERT ON *.* TO CURRENT_USER();
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
user host password insert_priv
|
||||
root localhost Y
|
||||
UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h;
|
||||
GRANT INSERT ON *.* TO CURRENT_USER() IDENTIFIED BY 'keksdose';
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
user host password insert_priv
|
||||
root localhost *0BB7188CF0DE9B403BA66E9DD810D82652D002EB Y
|
||||
UPDATE user SET password=@pwd WHERE user=@u AND host=@h;
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
user host password insert_priv
|
||||
root localhost Y
|
||||
FLUSH PRIVILEGES;
|
||||
USE test;
|
||||
End of 5.1 tests
|
||||
|
|
|
@ -1604,6 +1604,39 @@ str_to_date('', '%Y-%m-%d')
|
|||
0000-00-00
|
||||
DROP TABLE t1, t2;
|
||||
#
|
||||
# Bug#48459: valgrind errors with query using 'Range checked for each
|
||||
# record'
|
||||
#
|
||||
CREATE TABLE t1 (
|
||||
a INT,
|
||||
b CHAR(2),
|
||||
c INT,
|
||||
d INT,
|
||||
KEY ( c ),
|
||||
KEY ( d, a, b ( 2 ) ),
|
||||
KEY ( b ( 1 ) )
|
||||
);
|
||||
INSERT INTO t1 VALUES ( NULL, 'a', 1, 2 ), ( NULL, 'a', 1, 2 ),
|
||||
( 1, 'a', 1, 2 ), ( 1, 'a', 1, 2 );
|
||||
CREATE TABLE t2 (
|
||||
a INT,
|
||||
c INT,
|
||||
e INT,
|
||||
KEY ( e )
|
||||
);
|
||||
INSERT INTO t2 VALUES ( 1, 1, NULL ), ( 1, 1, NULL );
|
||||
# Should not give Valgrind warnings
|
||||
SELECT 1
|
||||
FROM t1, t2
|
||||
WHERE t1.d <> '1' AND t1.b > '1'
|
||||
AND t1.a = t2.a AND t1.c = t2.c;
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
DROP TABLE t1, t2;
|
||||
#
|
||||
# Bug #48665: sql-bench's insert test fails due to wrong result
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a));
|
||||
|
|
|
@ -6979,6 +6979,64 @@ CALL p1;
|
|||
ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1, t2;
|
||||
#
|
||||
# Bug#47627: SET @@{global.session}.local_variable in stored routine causes crash
|
||||
# Bug#48626: Crash or lost connection using SET for declared variables with @@
|
||||
#
|
||||
DROP PROCEDURE IF EXISTS p1;
|
||||
DROP PROCEDURE IF EXISTS p2;
|
||||
DROP PROCEDURE IF EXISTS p3;
|
||||
CREATE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET @@SESSION.v= 10;
|
||||
END//
|
||||
ERROR HY000: Unknown system variable 'v'
|
||||
CREATE PROCEDURE p2()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET v= 10;
|
||||
END//
|
||||
call p2()//
|
||||
CREATE PROCEDURE p3()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SELECT @@SESSION.v;
|
||||
END//
|
||||
ERROR HY000: Unknown system variable 'v'
|
||||
CREATE PROCEDURE p4()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET @@GLOBAL.v= 10;
|
||||
END//
|
||||
ERROR HY000: Unknown system variable 'v'
|
||||
CREATE PROCEDURE p5()
|
||||
BEGIN
|
||||
DECLARE init_connect INT DEFAULT 0;
|
||||
SET init_connect= 10;
|
||||
SET @@GLOBAL.init_connect= 'SELECT 1';
|
||||
SET @@SESSION.IDENTITY= 1;
|
||||
SELECT @@SESSION.IDENTITY;
|
||||
SELECT @@GLOBAL.init_connect;
|
||||
SELECT init_connect;
|
||||
END//
|
||||
CREATE PROCEDURE p6()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET @@v= 0;
|
||||
END//
|
||||
ERROR HY000: Unknown system variable 'v'
|
||||
SET @old_init_connect= @@GLOBAL.init_connect;
|
||||
CALL p5();
|
||||
@@SESSION.IDENTITY
|
||||
1
|
||||
@@GLOBAL.init_connect
|
||||
SELECT 1
|
||||
init_connect
|
||||
10
|
||||
SET @@GLOBAL.init_connect= @old_init_connect;
|
||||
DROP PROCEDURE p2;
|
||||
DROP PROCEDURE p5;
|
||||
# ------------------------------------------------------------------
|
||||
# -- End of 5.1 tests
|
||||
# ------------------------------------------------------------------
|
||||
|
|
|
@ -1630,3 +1630,287 @@ SELECT my_col FROM t1;
|
|||
my_col
|
||||
0.012345687012345687012345687012
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug#45261: Crash, stored procedure + decimal
|
||||
#
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001
|
||||
AS c1;
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,0) NO 0
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
99999999999999999999999999999999999999999999999999999999999999999
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.
|
||||
AS c1;
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,0) NO 0
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
99999999999999999999999999999999999999999999999999999999999999999
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */
|
||||
AS c1;
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,0) NO 0
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
99999999999999999999999999999999999999999999999999999999999999999
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
||||
AS c1;
|
||||
Warnings:
|
||||
Error 1292 Truncated incorrect DECIMAL value: ''
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,0) NO 0
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
99999999999999999999999999999999999999999999999999999999999999999
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */
|
||||
AS c1;
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
99999999999999999999999999999999999.999999999999999999999999999999
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(31,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
1.100000000000000000000000000000
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(31,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
1.100000000000000000000000000000
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
|
||||
AS c1;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(30,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
0.100000000000000000000000000000
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */
|
||||
AS c1;
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
99999999999999999999999999999999999.999999999999999999999999999999
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */
|
||||
AS c1;
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,1) NO 0.0
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
9999999999999999999999999999999999999999999999999999999999999999.9
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */
|
||||
AS c1;
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,1) NO 0.0
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
9999999999999999999999999999999999999999999999999999999999999999.9
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT
|
||||
.123456789012345678901234567890123456789012345678901234567890123456 /* 66 */
|
||||
AS c1;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(30,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
0.123456789012345678901234567890
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'c1' at row 1
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(33,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
123.123456789012345678901234567890
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1;
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,30) NO 0.000000000000000000000000000000
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
2.100000000000000000000000000000
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Test that the integer and decimal parts are properly calculated.
|
||||
#
|
||||
CREATE TABLE t1 (a DECIMAL(30,30));
|
||||
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
|
||||
CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'c1' at row 3
|
||||
DESC t2;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(32,30) YES NULL
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (a DECIMAL(30,30));
|
||||
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
|
||||
CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'c1' at row 1
|
||||
Note 1265 Data truncated for column 'c1' at row 2
|
||||
Note 1265 Data truncated for column 'c1' at row 3
|
||||
DESC t2;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(34,0) YES NULL
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (a DECIMAL(30,30));
|
||||
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
|
||||
CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'c1' at row 1
|
||||
DESC t2;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,30) YES NULL
|
||||
DROP TABLE t1,t2;
|
||||
#
|
||||
# Test that variables get maximum precision.
|
||||
#
|
||||
SET @decimal= 1.1;
|
||||
CREATE TABLE t1 SELECT @decimal AS c1;
|
||||
DESC t1;
|
||||
Field Type Null Key Default Extra
|
||||
c1 decimal(65,30) YES NULL
|
||||
SELECT * FROM t1;
|
||||
c1
|
||||
1.100000000000000000000000000000
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Bug #45261 : Crash, stored procedure + decimal
|
||||
# Original test by the reporter.
|
||||
#
|
||||
# should not crash
|
||||
CREATE TABLE t1
|
||||
SELECT .123456789012345678901234567890123456789012345678901234567890123456 AS a;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'a' at row 1
|
||||
DROP TABLE t1;
|
||||
CREATE PROCEDURE test_proc()
|
||||
BEGIN
|
||||
# The las non critical CUSER definition is:
|
||||
# DECLARE mycursor CURSOR FOR SELECT 1 %
|
||||
# .12345678912345678912345678912345678912345678912345678912345678912 AS my_col;
|
||||
DECLARE mycursor CURSOR FOR
|
||||
SELECT 1 %
|
||||
.123456789123456789123456789123456789123456789123456789123456789123456789123456789
|
||||
AS my_col;
|
||||
OPEN mycursor;
|
||||
CLOSE mycursor;
|
||||
END|
|
||||
# should not crash
|
||||
CALL test_proc();
|
||||
DROP PROCEDURE test_proc;
|
||||
#
|
||||
# Bug #48370 Absolutely wrong calculations with GROUP BY and
|
||||
# decimal fields when using IF
|
||||
#
|
||||
CREATE TABLE currencies (id int, rate decimal(16,4),
|
||||
PRIMARY KEY (id), KEY (rate));
|
||||
INSERT INTO currencies VALUES (11,0.7028);
|
||||
INSERT INTO currencies VALUES (1,1);
|
||||
CREATE TABLE payments (
|
||||
id int,
|
||||
supplier_id int,
|
||||
status int,
|
||||
currency_id int,
|
||||
vat decimal(7,4),
|
||||
PRIMARY KEY (id),
|
||||
KEY currency_id (currency_id),
|
||||
KEY supplier_id (supplier_id)
|
||||
);
|
||||
INSERT INTO payments (id,status,vat,supplier_id,currency_id) VALUES
|
||||
(3001,2,0.0000,344,11), (1,2,0.0000,1,1);
|
||||
CREATE TABLE sub_tasks (
|
||||
id int,
|
||||
currency_id int,
|
||||
price decimal(16,4),
|
||||
discount decimal(10,4),
|
||||
payment_id int,
|
||||
PRIMARY KEY (id),
|
||||
KEY currency_id (currency_id),
|
||||
KEY payment_id (payment_id)
|
||||
) ;
|
||||
INSERT INTO sub_tasks (id, price, discount, payment_id, currency_id) VALUES
|
||||
(52, 12.60, 0, 3001, 11), (56, 14.58, 0, 3001, 11);
|
||||
# should return 1 and the same values in col 2 and 3
|
||||
select STRAIGHT_JOIN
|
||||
(1 + PAY.vat) AS mult,
|
||||
SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 2)) *
|
||||
CUR.rate / CUR.rate, 2)
|
||||
) v_net_with_discount,
|
||||
SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 1)) *
|
||||
CUR.rate / CUR.rate , 2)
|
||||
* (1 + PAY.vat)
|
||||
) v_total
|
||||
from
|
||||
currencies CUR, payments PAY, sub_tasks SUB
|
||||
where
|
||||
SUB.payment_id = PAY.id and
|
||||
PAY.currency_id = CUR.id and
|
||||
PAY.id > 2
|
||||
group by PAY.id + 1;
|
||||
mult v_net_with_discount v_total
|
||||
1.0000 27.18 27.180000
|
||||
DROP TABLE currencies, payments, sub_tasks;
|
||||
End of 5.1 tests
|
||||
|
|
1
mysql-test/t/bug47671-master.opt
Normal file
1
mysql-test/t/bug47671-master.opt
Normal file
|
@ -0,0 +1 @@
|
|||
--default-character-set=utf8 --skip-character-set-client-handshake
|
6
mysql-test/t/bug47671.test
Normal file
6
mysql-test/t/bug47671.test
Normal file
|
@ -0,0 +1,6 @@
|
|||
--echo #
|
||||
--echo # Bug#47671 - wrong character-set after upgrade from 5.1.34 to 5.1.39
|
||||
--echo #
|
||||
--echo # Extract only charset information from 'status' command output using regex
|
||||
--replace_regex /.*mysql.*// /Connection.*// /Current.*// /SSL.*// /Using.*// /Server version.*// /Protocol.*// /UNIX.*// /Uptime.*// /Threads.*//
|
||||
--exec $MYSQL -u root test -e "status";
|
|
@ -1053,4 +1053,35 @@ ORDER BY max;
|
|||
--echo #
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#43668: Wrong comparison and MIN/MAX for YEAR(2)
|
||||
--echo #
|
||||
create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime);
|
||||
insert into t1 values
|
||||
(98,1998,19980101,"1998-01-01 00:00:00"),
|
||||
(00,2000,20000101,"2000-01-01 00:00:01"),
|
||||
(02,2002,20020101,"2002-01-01 23:59:59"),
|
||||
(60,2060,20600101,"2060-01-01 11:11:11"),
|
||||
(70,1970,19700101,"1970-11-11 22:22:22"),
|
||||
(NULL,NULL,NULL,NULL);
|
||||
select min(f1),max(f1) from t1;
|
||||
select min(f2),max(f2) from t1;
|
||||
select min(f3),max(f3) from t1;
|
||||
select min(f4),max(f4) from t1;
|
||||
select a.f1 as a, b.f1 as b, a.f1 > b.f1 as gt,
|
||||
a.f1 < b.f1 as lt, a.f1<=>b.f1 as eq
|
||||
from t1 a, t1 b;
|
||||
select a.f1 as a, b.f2 as b, a.f1 > b.f2 as gt,
|
||||
a.f1 < b.f2 as lt, a.f1<=>b.f2 as eq
|
||||
from t1 a, t1 b;
|
||||
select a.f1 as a, b.f3 as b, a.f1 > b.f3 as gt,
|
||||
a.f1 < b.f3 as lt, a.f1<=>b.f3 as eq
|
||||
from t1 a, t1 b;
|
||||
select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt,
|
||||
a.f1 < b.f4 as lt, a.f1<=>b.f4 as eq
|
||||
from t1 a, t1 b;
|
||||
select *, f1 = f2 from t1;
|
||||
drop table t1;
|
||||
--echo #
|
||||
--echo End of 5.1 tests
|
||||
|
||||
|
|
|
@ -632,5 +632,40 @@ DROP DATABASE db1;
|
|||
|
||||
--echo End of 5.0 tests
|
||||
|
||||
#
|
||||
# Bug #48319: Server crashes on "GRANT/REVOKE ... TO CURRENT_USER"
|
||||
#
|
||||
|
||||
# work out who we are.
|
||||
USE mysql;
|
||||
SELECT LEFT(CURRENT_USER(),INSTR(CURRENT_USER(),'@')-1) INTO @u;
|
||||
SELECT MID(CURRENT_USER(),INSTR(CURRENT_USER(),'@')+1) INTO @h;
|
||||
SELECT password FROM user WHERE user=@u AND host=@h INTO @pwd;
|
||||
|
||||
# show current privs.
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
|
||||
# toggle INSERT
|
||||
UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h;
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
|
||||
# show that GRANT ... TO CURRENT_USER() no longer crashes
|
||||
GRANT INSERT ON *.* TO CURRENT_USER();
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h;
|
||||
|
||||
# show that GRANT ... TO CURRENT_USER() IDENTIFIED BY ... works now
|
||||
GRANT INSERT ON *.* TO CURRENT_USER() IDENTIFIED BY 'keksdose';
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
|
||||
UPDATE user SET password=@pwd WHERE user=@u AND host=@h;
|
||||
SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h;
|
||||
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
USE test;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
||||
# Wait till we reached the initial number of concurrent sessions
|
||||
--source include/wait_until_count_sessions.inc
|
||||
|
|
|
@ -1260,6 +1260,39 @@ SELECT str_to_date('', '%Y-%m-%d');
|
|||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#48459: valgrind errors with query using 'Range checked for each
|
||||
--echo # record'
|
||||
--echo #
|
||||
CREATE TABLE t1 (
|
||||
a INT,
|
||||
b CHAR(2),
|
||||
c INT,
|
||||
d INT,
|
||||
KEY ( c ),
|
||||
KEY ( d, a, b ( 2 ) ),
|
||||
KEY ( b ( 1 ) )
|
||||
);
|
||||
|
||||
INSERT INTO t1 VALUES ( NULL, 'a', 1, 2 ), ( NULL, 'a', 1, 2 ),
|
||||
( 1, 'a', 1, 2 ), ( 1, 'a', 1, 2 );
|
||||
|
||||
CREATE TABLE t2 (
|
||||
a INT,
|
||||
c INT,
|
||||
e INT,
|
||||
KEY ( e )
|
||||
);
|
||||
|
||||
INSERT INTO t2 VALUES ( 1, 1, NULL ), ( 1, 1, NULL );
|
||||
|
||||
--echo # Should not give Valgrind warnings
|
||||
SELECT 1
|
||||
FROM t1, t2
|
||||
WHERE t1.d <> '1' AND t1.b > '1'
|
||||
AND t1.a = t2.a AND t1.c = t2.c;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #48665: sql-bench's insert test fails due to wrong result
|
||||
|
@ -1280,5 +1313,4 @@ SELECT * FROM t1 FORCE INDEX (PRIMARY)
|
|||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
|
|
@ -8263,6 +8263,73 @@ CALL p1;
|
|||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#47627: SET @@{global.session}.local_variable in stored routine causes crash
|
||||
--echo # Bug#48626: Crash or lost connection using SET for declared variables with @@
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
DROP PROCEDURE IF EXISTS p1;
|
||||
DROP PROCEDURE IF EXISTS p2;
|
||||
DROP PROCEDURE IF EXISTS p3;
|
||||
--enable_warnings
|
||||
|
||||
delimiter //;
|
||||
|
||||
--error ER_UNKNOWN_SYSTEM_VARIABLE
|
||||
CREATE PROCEDURE p1()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET @@SESSION.v= 10;
|
||||
END//
|
||||
|
||||
CREATE PROCEDURE p2()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET v= 10;
|
||||
END//
|
||||
call p2()//
|
||||
|
||||
--error ER_UNKNOWN_SYSTEM_VARIABLE
|
||||
CREATE PROCEDURE p3()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SELECT @@SESSION.v;
|
||||
END//
|
||||
|
||||
--error ER_UNKNOWN_SYSTEM_VARIABLE
|
||||
CREATE PROCEDURE p4()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET @@GLOBAL.v= 10;
|
||||
END//
|
||||
|
||||
CREATE PROCEDURE p5()
|
||||
BEGIN
|
||||
DECLARE init_connect INT DEFAULT 0;
|
||||
SET init_connect= 10;
|
||||
SET @@GLOBAL.init_connect= 'SELECT 1';
|
||||
SET @@SESSION.IDENTITY= 1;
|
||||
SELECT @@SESSION.IDENTITY;
|
||||
SELECT @@GLOBAL.init_connect;
|
||||
SELECT init_connect;
|
||||
END//
|
||||
|
||||
--error ER_UNKNOWN_SYSTEM_VARIABLE
|
||||
CREATE PROCEDURE p6()
|
||||
BEGIN
|
||||
DECLARE v INT DEFAULT 0;
|
||||
SET @@v= 0;
|
||||
END//
|
||||
|
||||
delimiter ;//
|
||||
|
||||
SET @old_init_connect= @@GLOBAL.init_connect;
|
||||
CALL p5();
|
||||
SET @@GLOBAL.init_connect= @old_init_connect;
|
||||
|
||||
DROP PROCEDURE p2;
|
||||
DROP PROCEDURE p5;
|
||||
|
||||
--echo # ------------------------------------------------------------------
|
||||
--echo # -- End of 5.1 tests
|
||||
|
|
|
@ -1286,3 +1286,229 @@ CREATE TABLE t1 SELECT 1 % .1234567891234567891234567891234567891234567891234567
|
|||
DESCRIBE t1;
|
||||
SELECT my_col FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#45261: Crash, stored procedure + decimal
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
/* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT
|
||||
.123456789012345678901234567890123456789012345678901234567890123456 /* 66 */
|
||||
AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Test that the integer and decimal parts are properly calculated.
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a DECIMAL(30,30));
|
||||
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
|
||||
CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1;
|
||||
DESC t2;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
CREATE TABLE t1 (a DECIMAL(30,30));
|
||||
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
|
||||
CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1;
|
||||
DESC t2;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
CREATE TABLE t1 (a DECIMAL(30,30));
|
||||
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
|
||||
CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1;
|
||||
DESC t2;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo #
|
||||
--echo # Test that variables get maximum precision.
|
||||
--echo #
|
||||
|
||||
SET @decimal= 1.1;
|
||||
CREATE TABLE t1 SELECT @decimal AS c1;
|
||||
DESC t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #45261 : Crash, stored procedure + decimal
|
||||
--echo # Original test by the reporter.
|
||||
--echo #
|
||||
|
||||
--echo # should not crash
|
||||
CREATE TABLE t1
|
||||
SELECT .123456789012345678901234567890123456789012345678901234567890123456 AS a;
|
||||
DROP TABLE t1;
|
||||
|
||||
delimiter |;
|
||||
CREATE PROCEDURE test_proc()
|
||||
BEGIN
|
||||
# The las non critical CUSER definition is:
|
||||
# DECLARE mycursor CURSOR FOR SELECT 1 %
|
||||
# .12345678912345678912345678912345678912345678912345678912345678912 AS my_col;
|
||||
DECLARE mycursor CURSOR FOR
|
||||
SELECT 1 %
|
||||
.123456789123456789123456789123456789123456789123456789123456789123456789123456789
|
||||
AS my_col;
|
||||
|
||||
OPEN mycursor;
|
||||
CLOSE mycursor;
|
||||
END|
|
||||
delimiter ;|
|
||||
--echo # should not crash
|
||||
CALL test_proc();
|
||||
DROP PROCEDURE test_proc;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #48370 Absolutely wrong calculations with GROUP BY and
|
||||
--echo # decimal fields when using IF
|
||||
--echo #
|
||||
|
||||
CREATE TABLE currencies (id int, rate decimal(16,4),
|
||||
PRIMARY KEY (id), KEY (rate));
|
||||
|
||||
INSERT INTO currencies VALUES (11,0.7028);
|
||||
INSERT INTO currencies VALUES (1,1);
|
||||
|
||||
CREATE TABLE payments (
|
||||
id int,
|
||||
supplier_id int,
|
||||
status int,
|
||||
currency_id int,
|
||||
vat decimal(7,4),
|
||||
PRIMARY KEY (id),
|
||||
KEY currency_id (currency_id),
|
||||
KEY supplier_id (supplier_id)
|
||||
);
|
||||
|
||||
INSERT INTO payments (id,status,vat,supplier_id,currency_id) VALUES
|
||||
(3001,2,0.0000,344,11), (1,2,0.0000,1,1);
|
||||
|
||||
CREATE TABLE sub_tasks (
|
||||
id int,
|
||||
currency_id int,
|
||||
price decimal(16,4),
|
||||
discount decimal(10,4),
|
||||
payment_id int,
|
||||
PRIMARY KEY (id),
|
||||
KEY currency_id (currency_id),
|
||||
KEY payment_id (payment_id)
|
||||
) ;
|
||||
|
||||
INSERT INTO sub_tasks (id, price, discount, payment_id, currency_id) VALUES
|
||||
(52, 12.60, 0, 3001, 11), (56, 14.58, 0, 3001, 11);
|
||||
|
||||
--echo # should return 1 and the same values in col 2 and 3
|
||||
select STRAIGHT_JOIN
|
||||
(1 + PAY.vat) AS mult,
|
||||
SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 2)) *
|
||||
CUR.rate / CUR.rate, 2)
|
||||
) v_net_with_discount,
|
||||
|
||||
SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 1)) *
|
||||
CUR.rate / CUR.rate , 2)
|
||||
* (1 + PAY.vat)
|
||||
) v_total
|
||||
from
|
||||
currencies CUR, payments PAY, sub_tasks SUB
|
||||
where
|
||||
SUB.payment_id = PAY.id and
|
||||
PAY.currency_id = CUR.id and
|
||||
PAY.id > 2
|
||||
group by PAY.id + 1;
|
||||
|
||||
DROP TABLE currencies, payments, sub_tasks;
|
||||
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
|
44
sql/field.cc
44
sql/field.cc
|
@ -2486,6 +2486,50 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg,
|
|||
}
|
||||
|
||||
|
||||
Field *Field_new_decimal::create_from_item (Item *item)
|
||||
{
|
||||
uint8 dec= item->decimals;
|
||||
uint8 intg= item->decimal_precision() - dec;
|
||||
uint32 len= item->max_length;
|
||||
|
||||
DBUG_ASSERT (item->result_type() == DECIMAL_RESULT);
|
||||
|
||||
/*
|
||||
Trying to put too many digits overall in a DECIMAL(prec,dec)
|
||||
will always throw a warning. We must limit dec to
|
||||
DECIMAL_MAX_SCALE however to prevent an assert() later.
|
||||
*/
|
||||
|
||||
if (dec > 0)
|
||||
{
|
||||
signed int overflow;
|
||||
|
||||
dec= min(dec, DECIMAL_MAX_SCALE);
|
||||
|
||||
/*
|
||||
If the value still overflows the field with the corrected dec,
|
||||
we'll throw out decimals rather than integers. This is still
|
||||
bad and of course throws a truncation warning.
|
||||
+1: for decimal point
|
||||
*/
|
||||
|
||||
const int required_length=
|
||||
my_decimal_precision_to_length(intg + dec, dec,
|
||||
item->unsigned_flag);
|
||||
|
||||
overflow= required_length - len;
|
||||
|
||||
if (overflow > 0)
|
||||
dec= max(0, dec - overflow); // too long, discard fract
|
||||
else
|
||||
/* Corrected value fits. */
|
||||
len= required_length;
|
||||
}
|
||||
return new Field_new_decimal(len, item->maybe_null, item->name,
|
||||
dec, item->unsigned_flag);
|
||||
}
|
||||
|
||||
|
||||
int Field_new_decimal::reset(void)
|
||||
{
|
||||
store_value(&decimal_zero);
|
||||
|
|
|
@ -807,6 +807,7 @@ public:
|
|||
uint is_equal(Create_field *new_field);
|
||||
virtual const uchar *unpack(uchar* to, const uchar *from,
|
||||
uint param_data, bool low_byte_first);
|
||||
static Field *create_from_item (Item *);
|
||||
};
|
||||
|
||||
|
||||
|
|
108
sql/item.cc
108
sql/item.cc
|
@ -4899,9 +4899,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
|
|||
switch (field_type()) {
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0,
|
||||
Field::NONE, name, decimals, 0,
|
||||
unsigned_flag);
|
||||
field= Field_new_decimal::create_from_item(this);
|
||||
break;
|
||||
case MYSQL_TYPE_TINY:
|
||||
field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
|
||||
|
@ -6957,7 +6955,7 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
|
|||
{
|
||||
switch (type) {
|
||||
case INT_RESULT:
|
||||
return new Item_cache_int();
|
||||
return new Item_cache_int(item->field_type());
|
||||
case REAL_RESULT:
|
||||
return new Item_cache_real();
|
||||
case DECIMAL_RESULT:
|
||||
|
@ -6975,8 +6973,9 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
|
|||
|
||||
void Item_cache::store(Item *item)
|
||||
{
|
||||
if (item)
|
||||
example= item;
|
||||
if (!item)
|
||||
null_value= TRUE;
|
||||
value_cached= FALSE;
|
||||
}
|
||||
|
||||
|
@ -6990,12 +6989,15 @@ void Item_cache::print(String *str, enum_query_type query_type)
|
|||
str->append(')');
|
||||
}
|
||||
|
||||
void Item_cache_int::cache_value()
|
||||
bool Item_cache_int::cache_value()
|
||||
{
|
||||
if (!example)
|
||||
return FALSE;
|
||||
value_cached= TRUE;
|
||||
value= example->val_int_result();
|
||||
null_value= example->null_value;
|
||||
unsigned_flag= example->unsigned_flag;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7012,8 +7014,8 @@ void Item_cache_int::store(Item *item, longlong val_arg)
|
|||
String *Item_cache_int::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
str->set(value, default_charset());
|
||||
return str;
|
||||
}
|
||||
|
@ -7022,8 +7024,8 @@ String *Item_cache_int::val_str(String *str)
|
|||
my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
|
||||
return decimal_val;
|
||||
}
|
||||
|
@ -7031,40 +7033,43 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
|
|||
double Item_cache_int::val_real()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0.0;
|
||||
return (double) value;
|
||||
}
|
||||
|
||||
longlong Item_cache_int::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
void Item_cache_real::cache_value()
|
||||
bool Item_cache_real::cache_value()
|
||||
{
|
||||
if (!example)
|
||||
return FALSE;
|
||||
value_cached= TRUE;
|
||||
value= example->val_result();
|
||||
null_value= example->null_value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
double Item_cache_real::val_real()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0.0;
|
||||
return value;
|
||||
}
|
||||
|
||||
longlong Item_cache_real::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0;
|
||||
return (longlong) rint(value);
|
||||
}
|
||||
|
||||
|
@ -7072,8 +7077,8 @@ longlong Item_cache_real::val_int()
|
|||
String* Item_cache_real::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
str->set_real(value, decimals, default_charset());
|
||||
return str;
|
||||
}
|
||||
|
@ -7082,27 +7087,30 @@ String* Item_cache_real::val_str(String *str)
|
|||
my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
|
||||
return decimal_val;
|
||||
}
|
||||
|
||||
|
||||
void Item_cache_decimal::cache_value()
|
||||
bool Item_cache_decimal::cache_value()
|
||||
{
|
||||
if (!example)
|
||||
return FALSE;
|
||||
value_cached= TRUE;
|
||||
my_decimal *val= example->val_decimal_result(&decimal_value);
|
||||
if (!(null_value= example->null_value) && val != &decimal_value)
|
||||
my_decimal2decimal(val, &decimal_value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
double Item_cache_decimal::val_real()
|
||||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
double res;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
|
||||
return res;
|
||||
}
|
||||
|
@ -7111,8 +7119,8 @@ longlong Item_cache_decimal::val_int()
|
|||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
longlong res;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0;
|
||||
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
|
||||
return res;
|
||||
}
|
||||
|
@ -7120,8 +7128,8 @@ longlong Item_cache_decimal::val_int()
|
|||
String* Item_cache_decimal::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
|
||||
&decimal_value);
|
||||
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
|
||||
|
@ -7131,14 +7139,16 @@ String* Item_cache_decimal::val_str(String *str)
|
|||
my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
|
||||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
return &decimal_value;
|
||||
}
|
||||
|
||||
|
||||
void Item_cache_str::cache_value()
|
||||
bool Item_cache_str::cache_value()
|
||||
{
|
||||
if (!example)
|
||||
return FALSE;
|
||||
value_cached= TRUE;
|
||||
value_buff.set(buffer, sizeof(buffer), example->collation.collation);
|
||||
value= example->str_result(&value_buff);
|
||||
|
@ -7157,6 +7167,7 @@ void Item_cache_str::cache_value()
|
|||
value_buff.copy(*value);
|
||||
value= &value_buff;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
double Item_cache_str::val_real()
|
||||
|
@ -7164,8 +7175,8 @@ double Item_cache_str::val_real()
|
|||
DBUG_ASSERT(fixed == 1);
|
||||
int err_not_used;
|
||||
char *end_not_used;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0.0;
|
||||
if (value)
|
||||
return my_strntod(value->charset(), (char*) value->ptr(),
|
||||
value->length(), &end_not_used, &err_not_used);
|
||||
|
@ -7177,8 +7188,8 @@ longlong Item_cache_str::val_int()
|
|||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
int err;
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0;
|
||||
if (value)
|
||||
return my_strntoll(value->charset(), value->ptr(),
|
||||
value->length(), 10, (char**) 0, &err);
|
||||
|
@ -7190,8 +7201,8 @@ longlong Item_cache_str::val_int()
|
|||
String* Item_cache_str::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -7199,8 +7210,8 @@ String* Item_cache_str::val_str(String *str)
|
|||
my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return NULL;
|
||||
if (value)
|
||||
string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
|
||||
else
|
||||
|
@ -7211,8 +7222,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
|
|||
|
||||
int Item_cache_str::save_in_field(Field *field, bool no_conversions)
|
||||
{
|
||||
if (!value_cached)
|
||||
cache_value();
|
||||
if (!value_cached && !cache_value())
|
||||
return 0;
|
||||
int res= Item_cache::save_in_field(field, no_conversions);
|
||||
return (is_varbinary && field->type() == MYSQL_TYPE_STRING &&
|
||||
value->length() < field->field_length) ? 1 : res;
|
||||
|
@ -7247,13 +7258,21 @@ bool Item_cache_row::setup(Item * item)
|
|||
|
||||
void Item_cache_row::store(Item * item)
|
||||
{
|
||||
example= item;
|
||||
if (!item)
|
||||
{
|
||||
null_value= TRUE;
|
||||
return;
|
||||
}
|
||||
for (uint i= 0; i < item_count; i++)
|
||||
values[i]->store(item->element_index(i));
|
||||
}
|
||||
|
||||
|
||||
void Item_cache_row::cache_value()
|
||||
bool Item_cache_row::cache_value()
|
||||
{
|
||||
if (!example)
|
||||
return FALSE;
|
||||
value_cached= TRUE;
|
||||
null_value= 0;
|
||||
example->bring_value();
|
||||
|
@ -7262,6 +7281,7 @@ void Item_cache_row::cache_value()
|
|||
values[i]->cache_value();
|
||||
null_value|= values[i]->null_value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
29
sql/item.h
29
sql/item.h
|
@ -2138,6 +2138,23 @@ public:
|
|||
save_in_field(result_field, no_conversions);
|
||||
}
|
||||
void cleanup();
|
||||
/*
|
||||
This method is used for debug purposes to print the name of an
|
||||
item to the debug log. The second use of this method is as
|
||||
a helper function of print() and error messages, where it is
|
||||
applicable. To suit both goals it should return a meaningful,
|
||||
distinguishable and sintactically correct string. This method
|
||||
should not be used for runtime type identification, use enum
|
||||
{Sum}Functype and Item_func::functype()/Item_sum::sum_func()
|
||||
instead.
|
||||
Added here, to the parent class of both Item_func and Item_sum_func.
|
||||
|
||||
NOTE: for Items inherited from Item_sum, func_name() return part of
|
||||
function name till first argument (including '(') to make difference in
|
||||
names for functions with 'distinct' clause and without 'distinct' and
|
||||
also to make printing of items inherited from Item_sum uniform.
|
||||
*/
|
||||
virtual const char *func_name() const= 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -2947,7 +2964,7 @@ public:
|
|||
return this == item;
|
||||
}
|
||||
virtual void store(Item *item);
|
||||
virtual void cache_value()= 0;
|
||||
virtual bool cache_value()= 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -2968,7 +2985,7 @@ public:
|
|||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type() const { return INT_RESULT; }
|
||||
bool result_as_longlong() { return TRUE; }
|
||||
void cache_value();
|
||||
bool cache_value();
|
||||
};
|
||||
|
||||
|
||||
|
@ -2984,7 +3001,7 @@ public:
|
|||
String* val_str(String *str);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type() const { return REAL_RESULT; }
|
||||
void cache_value();
|
||||
bool cache_value();
|
||||
};
|
||||
|
||||
|
||||
|
@ -3000,7 +3017,7 @@ public:
|
|||
String* val_str(String *str);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type() const { return DECIMAL_RESULT; }
|
||||
void cache_value();
|
||||
bool cache_value();
|
||||
};
|
||||
|
||||
|
||||
|
@ -3025,7 +3042,7 @@ public:
|
|||
enum Item_result result_type() const { return STRING_RESULT; }
|
||||
CHARSET_INFO *charset() const { return value->charset(); };
|
||||
int save_in_field(Field *field, bool no_conversions);
|
||||
void cache_value();
|
||||
bool cache_value();
|
||||
};
|
||||
|
||||
class Item_cache_row: public Item_cache
|
||||
|
@ -3094,7 +3111,7 @@ public:
|
|||
values= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
void cache_value();
|
||||
bool cache_value();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include "sql_select.h"
|
||||
|
||||
static bool convert_constant_item(THD *, Item_field *, Item **);
|
||||
static longlong
|
||||
get_year_value(THD *thd, Item ***item_arg, Item **cache_arg,
|
||||
Item *warn_item, bool *is_null);
|
||||
|
||||
static Item_result item_store_type(Item_result a, Item *item,
|
||||
my_bool unsigned_flag)
|
||||
|
@ -533,11 +536,12 @@ void Item_bool_func2::fix_length_and_dec()
|
|||
}
|
||||
|
||||
|
||||
int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
|
||||
int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type)
|
||||
{
|
||||
owner= item;
|
||||
func= comparator_matrix[type]
|
||||
[test(owner->functype() == Item_func::EQUAL_FUNC)];
|
||||
[is_owner_equal_func()];
|
||||
|
||||
switch (type) {
|
||||
case ROW_RESULT:
|
||||
{
|
||||
|
@ -557,7 +561,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
|
|||
my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
|
||||
return 1;
|
||||
}
|
||||
if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)))
|
||||
if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i),
|
||||
set_null))
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
@ -571,7 +576,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
|
|||
if (cmp_collation.set((*a)->collation, (*b)->collation) ||
|
||||
cmp_collation.derivation == DERIVATION_NONE)
|
||||
{
|
||||
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
|
||||
my_coll_agg_error((*a)->collation, (*b)->collation,
|
||||
owner->func_name());
|
||||
return 1;
|
||||
}
|
||||
if (cmp_collation.collation == &my_charset_bin)
|
||||
|
@ -881,7 +887,7 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
|
|||
}
|
||||
|
||||
|
||||
int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
||||
int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
|
||||
Item **a1, Item **a2,
|
||||
Item_result type)
|
||||
{
|
||||
|
@ -891,6 +897,8 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||
owner= owner_arg;
|
||||
a= a1;
|
||||
b= a2;
|
||||
owner= owner_arg;
|
||||
thd= current_thd;
|
||||
|
||||
if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
|
||||
{
|
||||
|
@ -921,9 +929,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||
b= (Item **)&b_cache;
|
||||
}
|
||||
}
|
||||
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
|
||||
is_nulls_eq= is_owner_equal_func();
|
||||
func= &Arg_comparator::compare_datetime;
|
||||
get_value_func= &get_datetime_value;
|
||||
get_value_a_func= &get_datetime_value;
|
||||
get_value_b_func= &get_datetime_value;
|
||||
return 0;
|
||||
}
|
||||
else if (type == STRING_RESULT && (*a)->field_type() == MYSQL_TYPE_TIME &&
|
||||
|
@ -932,9 +941,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||
/* Compare TIME values as integers. */
|
||||
a_cache= 0;
|
||||
b_cache= 0;
|
||||
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
|
||||
is_nulls_eq= is_owner_equal_func();
|
||||
func= &Arg_comparator::compare_datetime;
|
||||
get_value_func= &get_time_value;
|
||||
get_value_a_func= &get_time_value;
|
||||
get_value_b_func= &get_time_value;
|
||||
return 0;
|
||||
}
|
||||
else if (type == STRING_RESULT &&
|
||||
|
@ -943,9 +953,42 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||
{
|
||||
DTCollation coll;
|
||||
coll.set((*a)->collation.collation);
|
||||
if (agg_item_set_converter(coll, owner_arg->func_name(),
|
||||
if (agg_item_set_converter(coll, owner->func_name(),
|
||||
b, 1, MY_COLL_CMP_CONV, 1))
|
||||
return 1;
|
||||
} else if (type != ROW_RESULT && ((*a)->field_type() == MYSQL_TYPE_YEAR ||
|
||||
(*b)->field_type() == MYSQL_TYPE_YEAR))
|
||||
{
|
||||
is_nulls_eq= is_owner_equal_func();
|
||||
year_as_datetime= FALSE;
|
||||
|
||||
if ((*a)->is_datetime())
|
||||
{
|
||||
year_as_datetime= TRUE;
|
||||
get_value_a_func= &get_datetime_value;
|
||||
} else if ((*a)->field_type() == MYSQL_TYPE_YEAR)
|
||||
get_value_a_func= &get_year_value;
|
||||
else
|
||||
{
|
||||
/*
|
||||
Because convert_constant_item is called only for EXECUTE in PS mode
|
||||
the value of get_value_x_func set in PREPARE might be not
|
||||
valid for EXECUTE.
|
||||
*/
|
||||
get_value_a_func= NULL;
|
||||
}
|
||||
|
||||
if ((*b)->is_datetime())
|
||||
{
|
||||
year_as_datetime= TRUE;
|
||||
get_value_b_func= &get_datetime_value;
|
||||
} else if ((*b)->field_type() == MYSQL_TYPE_YEAR)
|
||||
get_value_b_func= &get_year_value;
|
||||
else
|
||||
get_value_b_func= NULL;
|
||||
|
||||
func= &Arg_comparator::compare_year;
|
||||
return 0;
|
||||
}
|
||||
|
||||
a= cache_converted_constant(thd, a, &a_cache, type);
|
||||
|
@ -988,11 +1031,11 @@ Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value,
|
|||
}
|
||||
|
||||
|
||||
void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
|
||||
void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg,
|
||||
Item **a1, Item **b1)
|
||||
{
|
||||
thd= current_thd;
|
||||
/* A caller will handle null values by itself. */
|
||||
owner= NULL;
|
||||
owner= owner_arg;
|
||||
a= a1;
|
||||
b= b1;
|
||||
a_type= (*a)->field_type();
|
||||
|
@ -1001,7 +1044,8 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
|
|||
b_cache= 0;
|
||||
is_nulls_eq= FALSE;
|
||||
func= &Arg_comparator::compare_datetime;
|
||||
get_value_func= &get_datetime_value;
|
||||
get_value_a_func= &get_datetime_value;
|
||||
get_value_b_func= &get_datetime_value;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1101,6 +1145,51 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
|
|||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Retrieves YEAR value of 19XX form from given item.
|
||||
|
||||
SYNOPSIS
|
||||
get_year_value()
|
||||
thd thread handle
|
||||
item_arg [in/out] item to retrieve YEAR value from
|
||||
cache_arg [in/out] pointer to place to store the caching item to
|
||||
warn_item [in] item for issuing the conversion warning
|
||||
is_null [out] TRUE <=> the item_arg is null
|
||||
|
||||
DESCRIPTION
|
||||
Retrieves the YEAR value of 19XX form from given item for comparison by the
|
||||
compare_year() function.
|
||||
|
||||
RETURN
|
||||
obtained value
|
||||
*/
|
||||
|
||||
static longlong
|
||||
get_year_value(THD *thd, Item ***item_arg, Item **cache_arg,
|
||||
Item *warn_item, bool *is_null)
|
||||
{
|
||||
longlong value= 0;
|
||||
Item *item= **item_arg;
|
||||
|
||||
value= item->val_int();
|
||||
*is_null= item->null_value;
|
||||
if (*is_null)
|
||||
return ~(ulonglong) 0;
|
||||
|
||||
/*
|
||||
Coerce value to the 19XX form in order to correctly compare
|
||||
YEAR(2) & YEAR(4) types.
|
||||
*/
|
||||
if (value < 70)
|
||||
value+= 100;
|
||||
if (value <= 1900)
|
||||
value+= 1900;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Compare items values as dates.
|
||||
|
||||
|
@ -1133,25 +1222,25 @@ int Arg_comparator::compare_datetime()
|
|||
longlong a_value, b_value;
|
||||
|
||||
/* Get DATE/DATETIME/TIME value of the 'a' item. */
|
||||
a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null);
|
||||
a_value= (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null);
|
||||
if (!is_nulls_eq && a_is_null)
|
||||
{
|
||||
if (owner)
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get DATE/DATETIME/TIME value of the 'b' item. */
|
||||
b_value= (*get_value_func)(thd, &b, &b_cache, *a, &b_is_null);
|
||||
b_value= (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null);
|
||||
if (a_is_null || b_is_null)
|
||||
{
|
||||
if (owner)
|
||||
if (set_null)
|
||||
owner->null_value= is_nulls_eq ? 0 : 1;
|
||||
return is_nulls_eq ? (a_is_null == b_is_null) : -1;
|
||||
}
|
||||
|
||||
/* Here we have two not-NULL values. */
|
||||
if (owner)
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
|
||||
/* Compare values. */
|
||||
|
@ -1164,14 +1253,16 @@ int Arg_comparator::compare_datetime()
|
|||
int Arg_comparator::compare_string()
|
||||
{
|
||||
String *res1,*res2;
|
||||
if ((res1= (*a)->val_str(&owner->tmp_value1)))
|
||||
if ((res1= (*a)->val_str(&value1)))
|
||||
{
|
||||
if ((res2= (*b)->val_str(&owner->tmp_value2)))
|
||||
if ((res2= (*b)->val_str(&value2)))
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
return sortcmp(res1,res2,cmp_collation.collation);
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1191,10 +1282,11 @@ int Arg_comparator::compare_string()
|
|||
int Arg_comparator::compare_binary_string()
|
||||
{
|
||||
String *res1,*res2;
|
||||
if ((res1= (*a)->val_str(&owner->tmp_value1)))
|
||||
if ((res1= (*a)->val_str(&value1)))
|
||||
{
|
||||
if ((res2= (*b)->val_str(&owner->tmp_value2)))
|
||||
if ((res2= (*b)->val_str(&value2)))
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
uint res1_length= res1->length();
|
||||
uint res2_length= res2->length();
|
||||
|
@ -1202,6 +1294,7 @@ int Arg_comparator::compare_binary_string()
|
|||
return cmp ? cmp : (int) (res1_length - res2_length);
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1215,8 +1308,8 @@ int Arg_comparator::compare_binary_string()
|
|||
int Arg_comparator::compare_e_string()
|
||||
{
|
||||
String *res1,*res2;
|
||||
res1= (*a)->val_str(&owner->tmp_value1);
|
||||
res2= (*b)->val_str(&owner->tmp_value2);
|
||||
res1= (*a)->val_str(&value1);
|
||||
res2= (*b)->val_str(&value2);
|
||||
if (!res1 || !res2)
|
||||
return test(res1 == res2);
|
||||
return test(sortcmp(res1, res2, cmp_collation.collation) == 0);
|
||||
|
@ -1226,8 +1319,8 @@ int Arg_comparator::compare_e_string()
|
|||
int Arg_comparator::compare_e_binary_string()
|
||||
{
|
||||
String *res1,*res2;
|
||||
res1= (*a)->val_str(&owner->tmp_value1);
|
||||
res2= (*b)->val_str(&owner->tmp_value2);
|
||||
res1= (*a)->val_str(&value1);
|
||||
res2= (*b)->val_str(&value2);
|
||||
if (!res1 || !res2)
|
||||
return test(res1 == res2);
|
||||
return test(stringcmp(res1, res2) == 0);
|
||||
|
@ -1248,12 +1341,14 @@ int Arg_comparator::compare_real()
|
|||
val2= (*b)->val_real();
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
if (val1 < val2) return -1;
|
||||
if (val1 == val2) return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1268,10 +1363,12 @@ int Arg_comparator::compare_decimal()
|
|||
my_decimal *val2= (*b)->val_decimal(&value2);
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
return my_decimal_cmp(val1, val2);
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1310,6 +1407,7 @@ int Arg_comparator::compare_real_fixed()
|
|||
val2= (*b)->val_real();
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
if (val1 == val2 || fabs(val1 - val2) < precision)
|
||||
return 0;
|
||||
|
@ -1318,6 +1416,7 @@ int Arg_comparator::compare_real_fixed()
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1341,12 +1440,14 @@ int Arg_comparator::compare_int_signed()
|
|||
longlong val2= (*b)->val_int();
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
if (val1 < val2) return -1;
|
||||
if (val1 == val2) return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1364,12 +1465,14 @@ int Arg_comparator::compare_int_unsigned()
|
|||
ulonglong val2= (*b)->val_int();
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
if (val1 < val2) return -1;
|
||||
if (val1 == val2) return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1387,6 +1490,7 @@ int Arg_comparator::compare_int_signed_unsigned()
|
|||
ulonglong uval2= (ulonglong)(*b)->val_int();
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
if (sval1 < 0 || (ulonglong)sval1 < uval2)
|
||||
return -1;
|
||||
|
@ -1395,6 +1499,7 @@ int Arg_comparator::compare_int_signed_unsigned()
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1412,6 +1517,7 @@ int Arg_comparator::compare_int_unsigned_signed()
|
|||
longlong sval2= (*b)->val_int();
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
if (sval2 < 0)
|
||||
return 1;
|
||||
|
@ -1422,6 +1528,7 @@ int Arg_comparator::compare_int_unsigned_signed()
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= 1;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1458,10 +1565,11 @@ int Arg_comparator::compare_row()
|
|||
for (uint i= 0; i<n; i++)
|
||||
{
|
||||
res= comparators[i].compare();
|
||||
if (owner->null_value)
|
||||
/* Aggregate functions don't need special null handling. */
|
||||
if (owner->null_value && owner->type() == Item::FUNC_ITEM)
|
||||
{
|
||||
// NULL was compared
|
||||
switch (owner->functype()) {
|
||||
switch (((Item_func*)owner)->functype()) {
|
||||
case Item_func::NE_FUNC:
|
||||
break; // NE never aborts on NULL even if abort_on_null is set
|
||||
case Item_func::LT_FUNC:
|
||||
|
@ -1470,7 +1578,7 @@ int Arg_comparator::compare_row()
|
|||
case Item_func::GE_FUNC:
|
||||
return -1; // <, <=, > and >= always fail on NULL
|
||||
default: // EQ_FUNC
|
||||
if (owner->abort_on_null)
|
||||
if (((Item_bool_func2*)owner)->abort_on_null)
|
||||
return -1; // We do not need correct NULL returning
|
||||
}
|
||||
was_null= 1;
|
||||
|
@ -1507,6 +1615,67 @@ int Arg_comparator::compare_e_row()
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Compare values as YEAR.
|
||||
|
||||
@details
|
||||
Compare items as YEAR for EQUAL_FUNC and for other comparison functions.
|
||||
The YEAR values of form 19XX are obtained with help of the get_year_value()
|
||||
function.
|
||||
If one of arguments is of DATE/DATETIME type its value is obtained
|
||||
with help of the get_datetime_value function. In this case YEAR values
|
||||
prior to comparison are converted to the ulonglong YYYY-00-00 00:00:00
|
||||
DATETIME form.
|
||||
If an argument type neither YEAR nor DATE/DATEIME then val_int function
|
||||
is used to obtain value for comparison.
|
||||
|
||||
RETURN
|
||||
If is_nulls_eq is TRUE:
|
||||
1 if items are equal or both are null
|
||||
0 otherwise
|
||||
If is_nulls_eq is FALSE:
|
||||
-1 a < b
|
||||
0 a == b or at least one of items is null
|
||||
1 a > b
|
||||
See the table:
|
||||
is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
|
||||
a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
|
||||
b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
|
||||
result | 1 | 0 | 0 |0/1| 0 | 0 | 0 |-1/0/1|
|
||||
*/
|
||||
|
||||
int Arg_comparator::compare_year()
|
||||
{
|
||||
bool a_is_null, b_is_null;
|
||||
ulonglong val1= get_value_a_func ?
|
||||
(*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null) :
|
||||
(*a)->val_int();
|
||||
ulonglong val2= get_value_b_func ?
|
||||
(*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null) :
|
||||
(*b)->val_int();
|
||||
if (!(*a)->null_value)
|
||||
{
|
||||
if (!(*b)->null_value)
|
||||
{
|
||||
if (set_null)
|
||||
owner->null_value= 0;
|
||||
/* Convert year to DATETIME of form YYYY-00-00 00:00:00 when necessary. */
|
||||
if((*a)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime)
|
||||
val1*= 10000000000LL;
|
||||
if((*b)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime)
|
||||
val2*= 10000000000LL;
|
||||
|
||||
if (val1 < val2) return is_nulls_eq ? 0 : -1;
|
||||
if (val1 == val2) return is_nulls_eq ? 1 : 0;
|
||||
return is_nulls_eq ? 0 : 1;
|
||||
}
|
||||
}
|
||||
if (set_null)
|
||||
owner->null_value= is_nulls_eq ? 0 : 1;
|
||||
return (is_nulls_eq && (*a)->null_value == (*b)->null_value) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void Item_func_truth::fix_length_and_dec()
|
||||
{
|
||||
maybe_null= 0;
|
||||
|
@ -1794,8 +1963,8 @@ longlong Item_func_lt::val_int()
|
|||
longlong Item_func_strcmp::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
String *a=args[0]->val_str(&tmp_value1);
|
||||
String *b=args[1]->val_str(&tmp_value2);
|
||||
String *a=args[0]->val_str(&cmp.value1);
|
||||
String *b=args[1]->val_str(&cmp.value2);
|
||||
if (!a || !b)
|
||||
{
|
||||
null_value=1;
|
||||
|
@ -2078,8 +2247,8 @@ void Item_func_between::fix_length_and_dec()
|
|||
|
||||
if (compare_as_dates)
|
||||
{
|
||||
ge_cmp.set_datetime_cmp_func(args, args + 1);
|
||||
le_cmp.set_datetime_cmp_func(args, args + 2);
|
||||
ge_cmp.set_datetime_cmp_func(this, args, args + 1);
|
||||
le_cmp.set_datetime_cmp_func(this, args, args + 2);
|
||||
}
|
||||
else if (time_items_found == 3)
|
||||
{
|
||||
|
@ -4407,13 +4576,13 @@ void Item_func_isnotnull::print(String *str, enum_query_type query_type)
|
|||
longlong Item_func_like::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
String* res = args[0]->val_str(&tmp_value1);
|
||||
String* res = args[0]->val_str(&cmp.value1);
|
||||
if (args[0]->null_value)
|
||||
{
|
||||
null_value=1;
|
||||
return 0;
|
||||
}
|
||||
String* res2 = args[1]->val_str(&tmp_value2);
|
||||
String* res2 = args[1]->val_str(&cmp.value2);
|
||||
if (args[1]->null_value)
|
||||
{
|
||||
null_value=1;
|
||||
|
@ -4437,7 +4606,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const
|
|||
{
|
||||
if (args[1]->const_item())
|
||||
{
|
||||
String* res2= args[1]->val_str((String *)&tmp_value2);
|
||||
String* res2= args[1]->val_str((String *)&cmp.value2);
|
||||
|
||||
if (!res2)
|
||||
return OPTIMIZE_NONE;
|
||||
|
@ -4468,7 +4637,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
|
|||
if (escape_item->const_item())
|
||||
{
|
||||
/* If we are on execution stage */
|
||||
String *escape_str= escape_item->val_str(&tmp_value1);
|
||||
String *escape_str= escape_item->val_str(&cmp.value1);
|
||||
if (escape_str)
|
||||
{
|
||||
if (escape_used_in_parsing && (
|
||||
|
@ -4523,7 +4692,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
|
|||
if (args[1]->const_item() && !use_strnxfrm(collation.collation) &&
|
||||
!(specialflag & SPECIAL_NO_NEW_FUNC))
|
||||
{
|
||||
String* res2 = args[1]->val_str(&tmp_value2);
|
||||
String* res2 = args[1]->val_str(&cmp.value2);
|
||||
if (!res2)
|
||||
return FALSE; // Null argument
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ class Arg_comparator: public Sql_alloc
|
|||
{
|
||||
Item **a, **b;
|
||||
arg_cmp_func func;
|
||||
Item_bool_func2 *owner;
|
||||
Item_result_field *owner;
|
||||
Arg_comparator *comparators; // used only for compare_row()
|
||||
double precision;
|
||||
/* Fields used in DATE/DATETIME comparison. */
|
||||
|
@ -40,30 +40,42 @@ class Arg_comparator: public Sql_alloc
|
|||
enum_field_types a_type, b_type; // Types of a and b items
|
||||
Item *a_cache, *b_cache; // Cached values of a and b items
|
||||
bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC
|
||||
bool set_null; // TRUE <=> set owner->null_value
|
||||
// when one of arguments is NULL.
|
||||
bool year_as_datetime; // TRUE <=> convert YEAR value to
|
||||
// the YYYY-00-00 00:00:00 DATETIME
|
||||
// format. See compare_year.
|
||||
enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
|
||||
CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
|
||||
longlong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg,
|
||||
longlong (*get_value_a_func)(THD *thd, Item ***item_arg, Item **cache_arg,
|
||||
Item *warn_item, bool *is_null);
|
||||
longlong (*get_value_b_func)(THD *thd, Item ***item_arg, Item **cache_arg,
|
||||
Item *warn_item, bool *is_null);
|
||||
public:
|
||||
DTCollation cmp_collation;
|
||||
/* Allow owner function to use string buffers. */
|
||||
String value1, value2;
|
||||
|
||||
Arg_comparator(): thd(0), a_cache(0), b_cache(0) {};
|
||||
Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0),
|
||||
year_as_datetime(0), get_value_a_func(0), get_value_b_func(0) {};
|
||||
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0),
|
||||
a_cache(0), b_cache(0) {};
|
||||
a_cache(0), b_cache(0), set_null(0), year_as_datetime(0),
|
||||
get_value_a_func(0), get_value_b_func(0) {};
|
||||
|
||||
int set_compare_func(Item_bool_func2 *owner, Item_result type);
|
||||
inline int set_compare_func(Item_bool_func2 *owner_arg)
|
||||
int set_compare_func(Item_result_field *owner, Item_result type);
|
||||
inline int set_compare_func(Item_result_field *owner_arg)
|
||||
{
|
||||
return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(),
|
||||
(*b)->result_type()));
|
||||
}
|
||||
int set_cmp_func(Item_bool_func2 *owner_arg,
|
||||
int set_cmp_func(Item_result_field *owner_arg,
|
||||
Item **a1, Item **a2,
|
||||
Item_result type);
|
||||
|
||||
inline int set_cmp_func(Item_bool_func2 *owner_arg,
|
||||
Item **a1, Item **a2)
|
||||
inline int set_cmp_func(Item_result_field *owner_arg,
|
||||
Item **a1, Item **a2, bool set_null_arg)
|
||||
{
|
||||
set_null= set_null_arg;
|
||||
return set_cmp_func(owner_arg, a1, a2,
|
||||
item_cmp_type((*a1)->result_type(),
|
||||
(*a2)->result_type()));
|
||||
|
@ -89,14 +101,20 @@ public:
|
|||
int compare_real_fixed();
|
||||
int compare_e_real_fixed();
|
||||
int compare_datetime(); // compare args[0] & args[1] as DATETIMEs
|
||||
int compare_year();
|
||||
|
||||
static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b,
|
||||
ulonglong *const_val_arg);
|
||||
|
||||
void set_datetime_cmp_func(Item **a1, Item **b1);
|
||||
Item** cache_converted_constant(THD *thd, Item **value, Item **cache,
|
||||
Item_result type);
|
||||
void set_datetime_cmp_func(Item_result_field *owner_arg, Item **a1, Item **b1);
|
||||
static arg_cmp_func comparator_matrix [5][2];
|
||||
inline bool is_owner_equal_func()
|
||||
{
|
||||
return (owner->type() == Item::FUNC_ITEM &&
|
||||
((Item_func*)owner)->functype() == Item_func::EQUAL_FUNC);
|
||||
}
|
||||
|
||||
friend class Item_func;
|
||||
};
|
||||
|
@ -326,7 +344,6 @@ class Item_bool_func2 :public Item_int_func
|
|||
{ /* Bool with 2 string args */
|
||||
protected:
|
||||
Arg_comparator cmp;
|
||||
String tmp_value1,tmp_value2;
|
||||
bool abort_on_null;
|
||||
|
||||
public:
|
||||
|
@ -335,7 +352,7 @@ public:
|
|||
void fix_length_and_dec();
|
||||
void set_cmp_func()
|
||||
{
|
||||
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1);
|
||||
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
|
||||
}
|
||||
optimize_type select_optimize() const { return OPTIMIZE_OP; }
|
||||
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
|
||||
|
|
|
@ -451,45 +451,8 @@ Field *Item_func::tmp_table_field(TABLE *table)
|
|||
return make_string_field(table);
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
uint8 dec= decimals;
|
||||
uint8 intg= decimal_precision() - dec;
|
||||
uint32 len= max_length;
|
||||
|
||||
/*
|
||||
Trying to put too many digits overall in a DECIMAL(prec,dec)
|
||||
will always throw a warning. We must limit dec to
|
||||
DECIMAL_MAX_SCALE however to prevent an assert() later.
|
||||
*/
|
||||
|
||||
if (dec > 0)
|
||||
{
|
||||
int overflow;
|
||||
|
||||
dec= min(dec, DECIMAL_MAX_SCALE);
|
||||
|
||||
/*
|
||||
If the value still overflows the field with the corrected dec,
|
||||
we'll throw out decimals rather than integers. This is still
|
||||
bad and of course throws a truncation warning.
|
||||
*/
|
||||
|
||||
const int required_length=
|
||||
my_decimal_precision_to_length(intg + dec, dec,
|
||||
unsigned_flag);
|
||||
|
||||
overflow= required_length - len;
|
||||
|
||||
if (overflow > 0)
|
||||
dec= max(0, dec - overflow); // too long, discard fract
|
||||
else
|
||||
/* Corrected value fits. */
|
||||
len= required_length;
|
||||
}
|
||||
|
||||
field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag);
|
||||
field= Field_new_decimal::create_from_item(this);
|
||||
break;
|
||||
}
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
// This case should never be chosen
|
||||
|
|
|
@ -124,17 +124,6 @@ public:
|
|||
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
|
||||
virtual bool have_rev_func() const { return 0; }
|
||||
virtual Item *key_item() const { return args[0]; }
|
||||
/*
|
||||
This method is used for debug purposes to print the name of an
|
||||
item to the debug log. The second use of this method is as
|
||||
a helper function of print(), where it is applicable.
|
||||
To suit both goals it should return a meaningful,
|
||||
distinguishable and sintactically correct string. This method
|
||||
should not be used for runtime type identification, use enum
|
||||
{Sum}Functype and Item_func::functype()/Item_sum::sum_func()
|
||||
instead.
|
||||
*/
|
||||
virtual const char *func_name() const= 0;
|
||||
virtual bool const_item() const { return const_item_cache; }
|
||||
inline Item **arguments() const { return args; }
|
||||
void set_arguments(List<Item> &list);
|
||||
|
|
|
@ -511,8 +511,8 @@ err:
|
|||
longlong Item_func_spatial_rel::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
String *res1= args[0]->val_str(&tmp_value1);
|
||||
String *res2= args[1]->val_str(&tmp_value2);
|
||||
String *res1= args[0]->val_str(&cmp.value1);
|
||||
String *res2= args[1]->val_str(&cmp.value2);
|
||||
Geometry_buffer buffer1, buffer2;
|
||||
Geometry *g1, *g2;
|
||||
MBR mbr1, mbr2;
|
||||
|
|
|
@ -132,6 +132,7 @@ public:
|
|||
@return the SELECT_LEX structure associated with this Item
|
||||
*/
|
||||
st_select_lex* get_select_lex();
|
||||
const char *func_name() const { DBUG_ASSERT(0); return "subselect"; }
|
||||
|
||||
friend class select_subselect;
|
||||
friend class Item_in_optimizer;
|
||||
|
|
282
sql/item_sum.cc
282
sql/item_sum.cc
|
@ -517,8 +517,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
|
|||
name, table->s, collation.collation);
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
field= new Field_new_decimal(max_length, maybe_null, name,
|
||||
decimals, unsigned_flag);
|
||||
field= Field_new_decimal::create_from_item(this);
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
|
@ -615,35 +614,6 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
|
|||
}
|
||||
|
||||
|
||||
Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
|
||||
:Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
|
||||
hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
|
||||
was_values(item->was_values)
|
||||
{
|
||||
/* copy results from old value */
|
||||
switch (hybrid_type) {
|
||||
case INT_RESULT:
|
||||
sum_int= item->sum_int;
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
my_decimal2decimal(&item->sum_dec, &sum_dec);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
sum= item->sum;
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
/*
|
||||
This can happen with ROLLUP. Note that the value is already
|
||||
copied at function call.
|
||||
*/
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
collation.set(item->collation);
|
||||
}
|
||||
|
||||
bool
|
||||
Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
||||
{
|
||||
|
@ -663,15 +633,12 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
|||
switch (hybrid_type= item->result_type()) {
|
||||
case INT_RESULT:
|
||||
max_length= 20;
|
||||
sum_int= 0;
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
max_length= item->max_length;
|
||||
my_decimal_set_zero(&sum_dec);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
max_length= float_length(decimals);
|
||||
sum= 0.0;
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
max_length= item->max_length;
|
||||
|
@ -680,10 +647,10 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
|||
default:
|
||||
DBUG_ASSERT(0);
|
||||
};
|
||||
setup(args[0], NULL);
|
||||
/* MIN/MAX can return NULL for empty set indepedent of the used column */
|
||||
maybe_null= 1;
|
||||
unsigned_flag=item->unsigned_flag;
|
||||
collation.set(item->collation);
|
||||
result_field=0;
|
||||
null_value=1;
|
||||
fix_length_and_dec();
|
||||
|
@ -701,6 +668,30 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
MIN/MAX function setup.
|
||||
|
||||
@param item argument of MIN/MAX function
|
||||
@param value_arg calculated value of MIN/MAX function
|
||||
|
||||
@details
|
||||
Setup cache/comparator of MIN/MAX functions. When called by the
|
||||
copy_or_same function value_arg parameter contains calculated value
|
||||
of the original MIN/MAX object and it is saved in this object's cache.
|
||||
*/
|
||||
|
||||
void Item_sum_hybrid::setup(Item *item, Item *value_arg)
|
||||
{
|
||||
value= Item_cache::get_cache(item);
|
||||
value->setup(item);
|
||||
value->store(value_arg);
|
||||
cmp= new Arg_comparator();
|
||||
cmp->set_cmp_func(this, args, (Item**)&value, FALSE);
|
||||
collation.set(item->collation);
|
||||
}
|
||||
|
||||
|
||||
Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
|
||||
uint convert_blob_length)
|
||||
{
|
||||
|
@ -1270,8 +1261,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
|
|||
0, name, &my_charset_bin);
|
||||
}
|
||||
else if (hybrid_type == DECIMAL_RESULT)
|
||||
field= new Field_new_decimal(max_length, maybe_null, name,
|
||||
decimals, unsigned_flag);
|
||||
field= Field_new_decimal::create_from_item(this);
|
||||
else
|
||||
field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
|
||||
if (field)
|
||||
|
@ -1592,19 +1582,7 @@ void Item_sum_variance::update_field()
|
|||
|
||||
void Item_sum_hybrid::clear()
|
||||
{
|
||||
switch (hybrid_type) {
|
||||
case INT_RESULT:
|
||||
sum_int= 0;
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
my_decimal_set_zero(&sum_dec);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
sum= 0.0;
|
||||
break;
|
||||
default:
|
||||
value.length(0);
|
||||
}
|
||||
value->null_value= 1;
|
||||
null_value= 1;
|
||||
}
|
||||
|
||||
|
@ -1613,30 +1591,7 @@ double Item_sum_hybrid::val_real()
|
|||
DBUG_ASSERT(fixed == 1);
|
||||
if (null_value)
|
||||
return 0.0;
|
||||
switch (hybrid_type) {
|
||||
case STRING_RESULT:
|
||||
{
|
||||
char *end_not_used;
|
||||
int err_not_used;
|
||||
String *res; res=val_str(&str_value);
|
||||
return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
|
||||
&end_not_used, &err_not_used) : 0.0);
|
||||
}
|
||||
case INT_RESULT:
|
||||
if (unsigned_flag)
|
||||
return ulonglong2double(sum_int);
|
||||
return (double) sum_int;
|
||||
case DECIMAL_RESULT:
|
||||
my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum);
|
||||
return sum;
|
||||
case REAL_RESULT:
|
||||
return sum;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
// This case should never be choosen
|
||||
DBUG_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
return value->val_real();
|
||||
}
|
||||
|
||||
longlong Item_sum_hybrid::val_int()
|
||||
|
@ -1644,18 +1599,7 @@ longlong Item_sum_hybrid::val_int()
|
|||
DBUG_ASSERT(fixed == 1);
|
||||
if (null_value)
|
||||
return 0;
|
||||
switch (hybrid_type) {
|
||||
case INT_RESULT:
|
||||
return sum_int;
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
longlong result;
|
||||
my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result);
|
||||
return sum_int;
|
||||
}
|
||||
default:
|
||||
return (longlong) rint(Item_sum_hybrid::val_real());
|
||||
}
|
||||
return value->val_int();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1664,26 +1608,7 @@ my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
|
|||
DBUG_ASSERT(fixed == 1);
|
||||
if (null_value)
|
||||
return 0;
|
||||
switch (hybrid_type) {
|
||||
case STRING_RESULT:
|
||||
string2my_decimal(E_DEC_FATAL_ERROR, &value, val);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
double2my_decimal(E_DEC_FATAL_ERROR, sum, val);
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
val= &sum_dec;
|
||||
break;
|
||||
case INT_RESULT:
|
||||
int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val);
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
// This case should never be choosen
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
return val; // Keep compiler happy
|
||||
return value->val_decimal(val);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1693,25 +1618,7 @@ Item_sum_hybrid::val_str(String *str)
|
|||
DBUG_ASSERT(fixed == 1);
|
||||
if (null_value)
|
||||
return 0;
|
||||
switch (hybrid_type) {
|
||||
case STRING_RESULT:
|
||||
return &value;
|
||||
case REAL_RESULT:
|
||||
str->set_real(sum,decimals, &my_charset_bin);
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str);
|
||||
return str;
|
||||
case INT_RESULT:
|
||||
str->set_int(sum_int, unsigned_flag, &my_charset_bin);
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
// This case should never be choosen
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
return str; // Keep compiler happy
|
||||
return value->val_str(str);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1720,7 +1627,9 @@ void Item_sum_hybrid::cleanup()
|
|||
DBUG_ENTER("Item_sum_hybrid::cleanup");
|
||||
Item_sum::cleanup();
|
||||
forced_const= FALSE;
|
||||
|
||||
if (cmp)
|
||||
delete cmp;
|
||||
cmp= 0;
|
||||
/*
|
||||
by default it is TRUE to avoid TRUE reporting by
|
||||
Item_func_not_all/Item_func_nop_all if this item was never called.
|
||||
|
@ -1741,128 +1650,46 @@ void Item_sum_hybrid::no_rows_in_result()
|
|||
|
||||
Item *Item_sum_min::copy_or_same(THD* thd)
|
||||
{
|
||||
return new (thd->mem_root) Item_sum_min(thd, this);
|
||||
Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this);
|
||||
item->setup(args[0], value);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
bool Item_sum_min::add()
|
||||
{
|
||||
switch (hybrid_type) {
|
||||
case STRING_RESULT:
|
||||
{
|
||||
String *result=args[0]->val_str(&tmp_value);
|
||||
/* args[0] < value */
|
||||
int res= cmp->compare();
|
||||
if (!args[0]->null_value &&
|
||||
(null_value || sortcmp(&value,result,collation.collation) > 0))
|
||||
(null_value || res < 0))
|
||||
{
|
||||
value.copy(*result);
|
||||
null_value=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INT_RESULT:
|
||||
{
|
||||
longlong nr=args[0]->val_int();
|
||||
if (!args[0]->null_value && (null_value ||
|
||||
(unsigned_flag &&
|
||||
(ulonglong) nr < (ulonglong) sum_int) ||
|
||||
(!unsigned_flag && nr < sum_int)))
|
||||
{
|
||||
sum_int=nr;
|
||||
null_value=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
|
||||
if (!args[0]->null_value &&
|
||||
(null_value || (my_decimal_cmp(&sum_dec, val) > 0)))
|
||||
{
|
||||
my_decimal2decimal(val, &sum_dec);
|
||||
value->store(args[0]);
|
||||
value->cache_value();
|
||||
null_value= 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
{
|
||||
double nr= args[0]->val_real();
|
||||
if (!args[0]->null_value && (null_value || nr < sum))
|
||||
{
|
||||
sum=nr;
|
||||
null_value=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
// This case should never be choosen
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Item *Item_sum_max::copy_or_same(THD* thd)
|
||||
{
|
||||
return new (thd->mem_root) Item_sum_max(thd, this);
|
||||
Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this);
|
||||
item->setup(args[0], value);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
bool Item_sum_max::add()
|
||||
{
|
||||
switch (hybrid_type) {
|
||||
case STRING_RESULT:
|
||||
{
|
||||
String *result=args[0]->val_str(&tmp_value);
|
||||
/* args[0] > value */
|
||||
int res= cmp->compare();
|
||||
if (!args[0]->null_value &&
|
||||
(null_value || sortcmp(&value,result,collation.collation) < 0))
|
||||
(null_value || res > 0))
|
||||
{
|
||||
value.copy(*result);
|
||||
null_value=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INT_RESULT:
|
||||
{
|
||||
longlong nr=args[0]->val_int();
|
||||
if (!args[0]->null_value && (null_value ||
|
||||
(unsigned_flag &&
|
||||
(ulonglong) nr > (ulonglong) sum_int) ||
|
||||
(!unsigned_flag && nr > sum_int)))
|
||||
{
|
||||
sum_int=nr;
|
||||
null_value=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
|
||||
if (!args[0]->null_value &&
|
||||
(null_value || (my_decimal_cmp(val, &sum_dec) > 0)))
|
||||
{
|
||||
my_decimal2decimal(val, &sum_dec);
|
||||
value->store(args[0]);
|
||||
value->cache_value();
|
||||
null_value= 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
{
|
||||
double nr= args[0]->val_real();
|
||||
if (!args[0]->null_value && (null_value || nr > sum))
|
||||
{
|
||||
sum=nr;
|
||||
null_value=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
// This case should never be choosen
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2226,14 +2053,15 @@ void Item_sum_hybrid::update_field()
|
|||
void
|
||||
Item_sum_hybrid::min_max_update_str_field()
|
||||
{
|
||||
String *res_str=args[0]->val_str(&value);
|
||||
DBUG_ASSERT(cmp);
|
||||
String *res_str=args[0]->val_str(&cmp->value1);
|
||||
|
||||
if (!args[0]->null_value)
|
||||
{
|
||||
result_field->val_str(&tmp_value);
|
||||
result_field->val_str(&cmp->value2);
|
||||
|
||||
if (result_field->is_null() ||
|
||||
(cmp_sign * sortcmp(res_str,&tmp_value,collation.collation)) < 0)
|
||||
(cmp_sign * sortcmp(res_str,&cmp->value2,collation.collation)) < 0)
|
||||
result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
|
||||
result_field->set_notnull();
|
||||
}
|
||||
|
|
|
@ -323,22 +323,6 @@ public:
|
|||
virtual void update_field()=0;
|
||||
virtual bool keep_field_type(void) const { return 0; }
|
||||
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
|
||||
/*
|
||||
This method is used for debug purposes to print the name of an
|
||||
item to the debug log. The second use of this method is as
|
||||
a helper function of print(), where it is applicable.
|
||||
To suit both goals it should return a meaningful,
|
||||
distinguishable and sintactically correct string. This method
|
||||
should not be used for runtime type identification, use enum
|
||||
{Sum}Functype and Item_func::functype()/Item_sum::sum_func()
|
||||
instead.
|
||||
|
||||
NOTE: for Items inherited from Item_sum, func_name() return part of
|
||||
function name till first argument (including '(') to make difference in
|
||||
names for functions with 'distinct' clause and without 'distinct' and
|
||||
also to make printing of items inherited from Item_sum uniform.
|
||||
*/
|
||||
virtual const char *func_name() const= 0;
|
||||
virtual Item *result_item(Field *field)
|
||||
{ return new Item_field(field); }
|
||||
table_map used_tables() const { return used_tables_cache; }
|
||||
|
@ -664,6 +648,7 @@ public:
|
|||
}
|
||||
void fix_length_and_dec() {}
|
||||
enum Item_result result_type () const { return hybrid_type; }
|
||||
const char *func_name() const { DBUG_ASSERT(0); return "avg_field"; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -732,6 +717,7 @@ public:
|
|||
}
|
||||
void fix_length_and_dec() {}
|
||||
enum Item_result result_type () const { return hybrid_type; }
|
||||
const char *func_name() const { DBUG_ASSERT(0); return "variance_field"; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -807,6 +793,7 @@ public:
|
|||
my_decimal *val_decimal(my_decimal *);
|
||||
enum Item_result result_type () const { return REAL_RESULT; }
|
||||
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;}
|
||||
const char *func_name() const { DBUG_ASSERT(0); return "std_field"; }
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -832,14 +819,13 @@ class Item_sum_std :public Item_sum_variance
|
|||
};
|
||||
|
||||
// This class is a string or number function depending on num_func
|
||||
|
||||
class Arg_comparator;
|
||||
class Item_cache;
|
||||
class Item_sum_hybrid :public Item_sum
|
||||
{
|
||||
protected:
|
||||
String value,tmp_value;
|
||||
double sum;
|
||||
longlong sum_int;
|
||||
my_decimal sum_dec;
|
||||
Item_cache *value;
|
||||
Arg_comparator *cmp;
|
||||
Item_result hybrid_type;
|
||||
enum_field_types hybrid_field_type;
|
||||
int cmp_sign;
|
||||
|
@ -847,12 +833,17 @@ protected:
|
|||
|
||||
public:
|
||||
Item_sum_hybrid(Item *item_par,int sign)
|
||||
:Item_sum(item_par), sum(0.0), sum_int(0),
|
||||
:Item_sum(item_par), value(0), cmp(0),
|
||||
hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG),
|
||||
cmp_sign(sign), was_values(TRUE)
|
||||
{ collation.set(&my_charset_bin); }
|
||||
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item);
|
||||
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
|
||||
:Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
|
||||
hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
|
||||
was_values(item->was_values)
|
||||
{ }
|
||||
bool fix_fields(THD *, Item **);
|
||||
void setup(Item *item, Item *value_arg);
|
||||
void clear();
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
|
|
|
@ -446,9 +446,9 @@ public:
|
|||
range_key, *range_key_flag);
|
||||
*range_key_flag|= key_tree->min_flag;
|
||||
if (key_tree->next_key_part &&
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE &&
|
||||
key_tree->next_key_part->part == key_tree->part+1 &&
|
||||
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) &&
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
|
||||
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)))
|
||||
res+= key_tree->next_key_part->store_min_key(key, range_key,
|
||||
range_key_flag);
|
||||
return res;
|
||||
|
@ -462,9 +462,9 @@ public:
|
|||
range_key, *range_key_flag);
|
||||
(*range_key_flag)|= key_tree->max_flag;
|
||||
if (key_tree->next_key_part &&
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE &&
|
||||
key_tree->next_key_part->part == key_tree->part+1 &&
|
||||
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) &&
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
|
||||
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
|
||||
res+= key_tree->next_key_part->store_max_key(key, range_key,
|
||||
range_key_flag);
|
||||
return res;
|
||||
|
@ -1700,6 +1700,7 @@ SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent,
|
|||
tmp->prev= *next_arg; // Link into next/prev chain
|
||||
(*next_arg)->next=tmp;
|
||||
(*next_arg)= tmp;
|
||||
tmp->part= this->part;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7290,15 +7291,13 @@ int test_rb_tree(SEL_ARG *element,SEL_ARG *parent)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Count how many times SEL_ARG graph "root" refers to its part "key"
|
||||
/**
|
||||
Count how many times SEL_ARG graph "root" refers to its part "key" via
|
||||
transitive closure.
|
||||
|
||||
SYNOPSIS
|
||||
count_key_part_usage()
|
||||
root An RB-Root node in a SEL_ARG graph.
|
||||
key Another RB-Root node in that SEL_ARG graph.
|
||||
@param root An RB-Root node in a SEL_ARG graph.
|
||||
@param key Another RB-Root node in that SEL_ARG graph.
|
||||
|
||||
DESCRIPTION
|
||||
The passed "root" node may refer to "key" node via root->next_key_part,
|
||||
root->next->n
|
||||
|
||||
|
@ -7330,7 +7329,7 @@ int test_rb_tree(SEL_ARG *element,SEL_ARG *parent)
|
|||
... +---+ $ |
|
||||
| |------------+
|
||||
+---+ $
|
||||
RETURN
|
||||
@return
|
||||
Number of links to "key" from nodes reachable from "root".
|
||||
*/
|
||||
|
||||
|
@ -7586,8 +7585,8 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree,
|
|||
param->first_null_comp= key_tree->part+1;
|
||||
|
||||
if (key_tree->next_key_part &&
|
||||
key_tree->next_key_part->part == key_tree->part+1 &&
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE &&
|
||||
key_tree->next_key_part->part == key_tree->part+1)
|
||||
{ // const key as prefix
|
||||
if (min_key_length == max_key_length &&
|
||||
!memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) &&
|
||||
|
@ -7868,8 +7867,8 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
|
|||
&tmp_max_key,max_key_flag);
|
||||
|
||||
if (key_tree->next_key_part &&
|
||||
key_tree->next_key_part->part == key_tree->part+1 &&
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
|
||||
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE &&
|
||||
key_tree->next_key_part->part == key_tree->part+1)
|
||||
{ // const key as prefix
|
||||
if ((tmp_min_key - min_key) == (tmp_max_key - max_key) &&
|
||||
memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 &&
|
||||
|
|
|
@ -3462,6 +3462,13 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
|
|||
result= TRUE;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
No User, but a password?
|
||||
They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... !
|
||||
Get the current user, and shallow-copy the new password to them!
|
||||
*/
|
||||
if (!tmp_Str->user.str && tmp_Str->password.str)
|
||||
Str->password= tmp_Str->password;
|
||||
if (replace_user_table(thd, tables[0].table, *Str,
|
||||
(!db ? rights : 0), revoke_grant, create_new_users,
|
||||
test(thd->variables.sql_mode &
|
||||
|
|
|
@ -7652,6 +7652,9 @@ void get_default_definer(THD *thd, LEX_USER *definer)
|
|||
|
||||
definer->host.str= (char *) sctx->priv_host;
|
||||
definer->host.length= strlen(definer->host.str);
|
||||
|
||||
definer->password.str= NULL;
|
||||
definer->password.length= 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7703,6 +7706,8 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
|
|||
|
||||
definer->user= *user_name;
|
||||
definer->host= *host_name;
|
||||
definer->password.str= NULL;
|
||||
definer->password.length= 0;
|
||||
|
||||
return definer;
|
||||
}
|
||||
|
|
|
@ -9469,47 +9469,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
|
|||
new_field->set_derivation(item->collation.derivation);
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
uint8 dec= item->decimals;
|
||||
uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec;
|
||||
uint32 len= item->max_length;
|
||||
|
||||
/*
|
||||
Trying to put too many digits overall in a DECIMAL(prec,dec)
|
||||
will always throw a warning. We must limit dec to
|
||||
DECIMAL_MAX_SCALE however to prevent an assert() later.
|
||||
*/
|
||||
|
||||
if (dec > 0)
|
||||
{
|
||||
signed int overflow;
|
||||
|
||||
dec= min(dec, DECIMAL_MAX_SCALE);
|
||||
|
||||
/*
|
||||
If the value still overflows the field with the corrected dec,
|
||||
we'll throw out decimals rather than integers. This is still
|
||||
bad and of course throws a truncation warning.
|
||||
+1: for decimal point
|
||||
*/
|
||||
|
||||
const int required_length=
|
||||
my_decimal_precision_to_length(intg + dec, dec,
|
||||
item->unsigned_flag);
|
||||
|
||||
overflow= required_length - len;
|
||||
|
||||
if (overflow > 0)
|
||||
dec= max(0, dec - overflow); // too long, discard fract
|
||||
else
|
||||
/* Corrected value fits. */
|
||||
len= required_length;
|
||||
}
|
||||
|
||||
new_field= new Field_new_decimal(len, maybe_null, item->name,
|
||||
dec, item->unsigned_flag);
|
||||
new_field= Field_new_decimal::create_from_item(item);
|
||||
break;
|
||||
}
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
// This case should never be choosen
|
||||
|
|
252
sql/sql_yacc.yy
252
sql/sql_yacc.yy
|
@ -389,6 +389,138 @@ void case_stmt_action_end_case(LEX *lex, bool simple)
|
|||
lex->sphead->do_cont_backpatch();
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp)
|
||||
{
|
||||
tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length);
|
||||
|
||||
if (tmp->var == NULL)
|
||||
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str);
|
||||
else
|
||||
tmp->base_name= null_lex_str;
|
||||
|
||||
return thd->is_error();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper action for a SET statement.
|
||||
Used to push a system variable into the assignment list.
|
||||
|
||||
@param thd the current thread
|
||||
@param tmp the system variable with base name
|
||||
@param var_type the scope of the variable
|
||||
@param val the value being assigned to the variable
|
||||
|
||||
@return TRUE if error, FALSE otherwise.
|
||||
*/
|
||||
|
||||
static bool
|
||||
set_system_variable(THD *thd, struct sys_var_with_base *tmp,
|
||||
enum enum_var_type var_type, Item *val)
|
||||
{
|
||||
set_var *var;
|
||||
LEX *lex= thd->lex;
|
||||
|
||||
/* No AUTOCOMMIT from a stored function or trigger. */
|
||||
if (lex->spcont && tmp->var == &sys_autocommit)
|
||||
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
|
||||
|
||||
if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val)))
|
||||
return TRUE;
|
||||
|
||||
return lex->var_list.push_back(var);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper action for a SET statement.
|
||||
Used to push a SP local variable into the assignment list.
|
||||
|
||||
@param thd the current thread
|
||||
@param var_type the SP local variable
|
||||
@param val the value being assigned to the variable
|
||||
|
||||
@return TRUE if error, FALSE otherwise.
|
||||
*/
|
||||
|
||||
static bool
|
||||
set_local_variable(THD *thd, sp_variable_t *spv, Item *val)
|
||||
{
|
||||
Item *it;
|
||||
LEX *lex= thd->lex;
|
||||
sp_instr_set *sp_set;
|
||||
|
||||
if (val)
|
||||
it= val;
|
||||
else if (spv->dflt)
|
||||
it= spv->dflt;
|
||||
else
|
||||
{
|
||||
it= new (thd->mem_root) Item_null();
|
||||
if (it == NULL)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
sp_set= new sp_instr_set(lex->sphead->instructions(), lex->spcont,
|
||||
spv->offset, it, spv->type, lex, TRUE);
|
||||
|
||||
return (sp_set == NULL || lex->sphead->add_instr(sp_set));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper action for a SET statement.
|
||||
Used to SET a field of NEW row.
|
||||
|
||||
@param thd the current thread
|
||||
@param name the field name
|
||||
@param val the value being assigned to the row
|
||||
|
||||
@return TRUE if error, FALSE otherwise.
|
||||
*/
|
||||
|
||||
static bool
|
||||
set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
Item_trigger_field *trg_fld;
|
||||
sp_instr_set_trigger_field *sp_fld;
|
||||
|
||||
/* QQ: Shouldn't this be field's default value ? */
|
||||
if (! val)
|
||||
val= new Item_null();
|
||||
|
||||
DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE &&
|
||||
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
|
||||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
|
||||
|
||||
trg_fld= new (thd->mem_root)
|
||||
Item_trigger_field(lex->current_context(),
|
||||
Item_trigger_field::NEW_ROW,
|
||||
name->str, UPDATE_ACL, FALSE);
|
||||
|
||||
if (trg_fld == NULL)
|
||||
return TRUE;
|
||||
|
||||
sp_fld= new sp_instr_set_trigger_field(lex->sphead->instructions(),
|
||||
lex->spcont, trg_fld, val, lex);
|
||||
|
||||
if (sp_fld == NULL)
|
||||
return TRUE;
|
||||
|
||||
/*
|
||||
Let us add this item to list of all Item_trigger_field
|
||||
objects in trigger.
|
||||
*/
|
||||
lex->trg_table_fields.link_in_list((uchar *) trg_fld,
|
||||
(uchar **) &trg_fld->next_trg_field);
|
||||
|
||||
return lex->sphead->add_instr(sp_fld);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
|
||||
See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
|
||||
|
@ -11830,98 +11962,42 @@ sys_option_value:
|
|||
option_type internal_variable_name equal set_expr_or_default
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
LEX *lex=Lex;
|
||||
LEX *lex= Lex;
|
||||
LEX_STRING *name= &$2.base_name;
|
||||
|
||||
if ($2.var == trg_new_row_fake_var)
|
||||
{
|
||||
/* We are in trigger and assigning value to field of new row */
|
||||
Item *it;
|
||||
Item_trigger_field *trg_fld;
|
||||
sp_instr_set_trigger_field *sp_fld;
|
||||
LINT_INIT(sp_fld);
|
||||
if ($1)
|
||||
{
|
||||
my_parse_error(ER(ER_SYNTAX_ERROR));
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
if ($4)
|
||||
it= $4;
|
||||
else
|
||||
{
|
||||
/* QQ: Shouldn't this be field's default value ? */
|
||||
it= new Item_null();
|
||||
}
|
||||
|
||||
DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE &&
|
||||
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
|
||||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
|
||||
|
||||
trg_fld= new (thd->mem_root)
|
||||
Item_trigger_field(Lex->current_context(),
|
||||
Item_trigger_field::NEW_ROW,
|
||||
$2.base_name.str,
|
||||
UPDATE_ACL, FALSE);
|
||||
if (trg_fld == NULL)
|
||||
MYSQL_YYABORT;
|
||||
|
||||
sp_fld= new sp_instr_set_trigger_field(lex->sphead->
|
||||
instructions(),
|
||||
lex->spcont,
|
||||
trg_fld,
|
||||
it, lex);
|
||||
if (sp_fld == NULL)
|
||||
MYSQL_YYABORT;
|
||||
|
||||
/*
|
||||
Let us add this item to list of all Item_trigger_field
|
||||
objects in trigger.
|
||||
*/
|
||||
lex->trg_table_fields.link_in_list((uchar *)trg_fld,
|
||||
(uchar **) &trg_fld->
|
||||
next_trg_field);
|
||||
|
||||
if (lex->sphead->add_instr(sp_fld))
|
||||
if (set_trigger_new_row(YYTHD, name, $4))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
else if ($2.var)
|
||||
{ /* System variable */
|
||||
{
|
||||
if ($1)
|
||||
lex->option_type= $1;
|
||||
set_var *var= new set_var(lex->option_type, $2.var,
|
||||
&$2.base_name, $4);
|
||||
if (var == NULL)
|
||||
|
||||
/* It is a system variable. */
|
||||
if (set_system_variable(thd, &$2, lex->option_type, $4))
|
||||
MYSQL_YYABORT;
|
||||
lex->var_list.push_back(var);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An SP local variable */
|
||||
sp_pcontext *ctx= lex->spcont;
|
||||
sp_variable_t *spv;
|
||||
sp_instr_set *sp_set;
|
||||
Item *it;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
sp_variable_t *spv= spc->find_variable(name);
|
||||
|
||||
if ($1)
|
||||
{
|
||||
my_parse_error(ER(ER_SYNTAX_ERROR));
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
|
||||
spv= ctx->find_variable(&$2.base_name);
|
||||
|
||||
if ($4)
|
||||
it= $4;
|
||||
else if (spv->dflt)
|
||||
it= spv->dflt;
|
||||
else
|
||||
{
|
||||
it= new (thd->mem_root) Item_null();
|
||||
if (it == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
|
||||
spv->offset, it, spv->type, lex, TRUE);
|
||||
if (sp_set == NULL ||
|
||||
lex->sphead->add_instr(sp_set))
|
||||
/* It is a local variable. */
|
||||
if (set_local_variable(thd, spv, $4))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
}
|
||||
|
@ -11957,11 +12033,16 @@ option_value:
|
|||
}
|
||||
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
set_var *var= new set_var($3, $4.var, &$4.base_name, $6);
|
||||
if (var == NULL)
|
||||
THD *thd= YYTHD;
|
||||
struct sys_var_with_base tmp= $4;
|
||||
/* Lookup if necessary: must be a system variable. */
|
||||
if (tmp.var == NULL)
|
||||
{
|
||||
if (find_sys_var_null_base(thd, &tmp))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
if (set_system_variable(thd, &tmp, $3, $6))
|
||||
MYSQL_YYABORT;
|
||||
lex->var_list.push_back(var);
|
||||
}
|
||||
| charset old_or_new_charset_name_or_default
|
||||
{
|
||||
|
@ -12054,31 +12135,26 @@ internal_variable_name:
|
|||
ident
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
sp_pcontext *spc= thd->lex->spcont;
|
||||
sp_variable_t *spv;
|
||||
|
||||
/* We have to lookup here since local vars can shadow sysvars */
|
||||
/* Best effort lookup for system variable. */
|
||||
if (!spc || !(spv = spc->find_variable(&$1)))
|
||||
{
|
||||
struct sys_var_with_base tmp= {NULL, $1};
|
||||
|
||||
/* Not an SP local variable */
|
||||
sys_var *tmp=find_sys_var(thd, $1.str, $1.length);
|
||||
if (!tmp)
|
||||
if (find_sys_var_null_base(thd, &tmp))
|
||||
MYSQL_YYABORT;
|
||||
$$.var= tmp;
|
||||
$$.base_name= null_lex_str;
|
||||
if (spc && tmp == &sys_autocommit)
|
||||
{
|
||||
/*
|
||||
We don't allow setting AUTOCOMMIT from a stored function
|
||||
or trigger.
|
||||
*/
|
||||
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
|
||||
}
|
||||
|
||||
$$= tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An SP local variable */
|
||||
/*
|
||||
Possibly an SP local variable (or a shadowed sysvar).
|
||||
Will depend on the context of the SET statement.
|
||||
*/
|
||||
$$.var= NULL;
|
||||
$$.base_name= $1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue