Automerge of mysql-5.1-bugteam into mysql-trunk-merge.

This commit is contained in:
Alexey Kopytov 2009-11-26 14:46:59 +03:00
commit 084ffd12a3
36 changed files with 1680 additions and 624 deletions

View file

@ -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 : "";

View file

@ -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);

View file

@ -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);

View file

@ -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)
{

View file

@ -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

View file

@ -50,7 +50,6 @@ EXPORTS
mysql_next_result
mysql_num_fields
mysql_num_rows
mysql_odbc_escape_string
mysql_options
mysql_ping
mysql_query

View 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
--------------

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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
# ------------------------------------------------------------------

View file

@ -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

View file

@ -0,0 +1 @@
--default-character-set=utf8 --skip-character-set-client-handshake

View 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";

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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 *);
};

View file

@ -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;
}

View file

@ -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();
};

View file

@ -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

View file

@ -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; }

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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();
}

View file

@ -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();

View file

@ -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 &&

View file

@ -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 &

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}