Auto-merge from mysql-5.1.

This commit is contained in:
Alexander Nozdrin 2009-11-05 15:13:16 +03:00
commit 3e2c9aac11
18 changed files with 312 additions and 525 deletions

View File

@ -48,6 +48,16 @@ DROP TABLE IF EXISTS tmp2, t;
--enable_warnings --enable_warnings
SELECT GET_LOCK("a",10); SELECT GET_LOCK("a",10);
#
# BUG48216 Replication fails on all slaves after upgrade to 5.0.86 on master
#
# When the session is closed, any temporary tables of the session are dropped
# and are binlogged. But it will be binlogged with a wrong database name when
# the length of the database name('drop-temp-table-test') is greater than the
# current database name('test').
#
USE test;
disconnect con1; disconnect con1;
connection con2; connection con2;

View File

@ -895,3 +895,72 @@ t1.a < (select t4.a+10
from t4, t5 limit 2)); from t4, t5 limit 2));
ERROR 21000: Subquery returns more than 1 row ERROR 21000: Subquery returns more than 1 row
drop table t0, t1, t2, t3, t4, t5; drop table t0, t1, t2, t3, t4, t5;
#
# BUG#48177 - SELECTs with NOT IN subqueries containing NULL
# values return too many records
#
CREATE TABLE t1 (
i1 int DEFAULT NULL,
i2 int DEFAULT NULL
) ;
INSERT INTO t1 VALUES (1, NULL);
INSERT INTO t1 VALUES (2, 3);
INSERT INTO t1 VALUES (4, NULL);
INSERT INTO t1 VALUES (4, 0);
INSERT INTO t1 VALUES (NULL, NULL);
CREATE TABLE t2 (
i1 int DEFAULT NULL,
i2 int DEFAULT NULL
) ;
INSERT INTO t2 VALUES (4, NULL);
INSERT INTO t2 VALUES (5, 0);
Data in t1
SELECT i1, i2 FROM t1;
i1 i2
1 NULL
2 3
4 NULL
4 0
NULL NULL
Data in subquery (should be filtered out)
SELECT i1, i2 FROM t2 ORDER BY i1;
i1 i2
4 NULL
5 0
FLUSH STATUS;
SELECT i1, i2
FROM t1
WHERE (i1, i2)
NOT IN (SELECT i1, i2 FROM t2);
i1 i2
1 NULL
2 3
# Check that the subquery only has to be evaluated once
# for all-NULL values even though there are two (NULL,NULL) records
# Baseline:
SHOW STATUS LIKE '%Handler_read_rnd_next';
Variable_name Value
Handler_read_rnd_next 17
INSERT INTO t1 VALUES (NULL, NULL);
FLUSH STATUS;
SELECT i1, i2
FROM t1
WHERE (i1, i2)
NOT IN (SELECT i1, i2 FROM t2);
i1 i2
1 NULL
2 3
# Handler_read_rnd_next should be one more than baseline
# (read record from t1, but do not read from t2)
SHOW STATUS LIKE '%Handler_read_rnd_next';
Variable_name Value
Handler_read_rnd_next 18
DROP TABLE t1,t2;
End of 5.1 tests

View File

@ -1495,9 +1495,9 @@ CREATE TABLE t1 (a int DEFAULT NULL, b int DEFAULT NULL);
INSERT INTO t1 VALUES (3,30), (1,10), (2,10); INSERT INTO t1 VALUES (3,30), (1,10), (2,10);
SELECT a+CAST(1 AS decimal(65,30)) AS aa, SUM(b) FROM t1 GROUP BY aa; SELECT a+CAST(1 AS decimal(65,30)) AS aa, SUM(b) FROM t1 GROUP BY aa;
aa SUM(b) aa SUM(b)
2.00000000000000000000000000000 10 2.000000000000000000000000000000 10
3.00000000000000000000000000000 10 3.000000000000000000000000000000 10
4.00000000000000000000000000000 30 4.000000000000000000000000000000 30
SELECT a+CAST(1 AS decimal(65,31)) AS aa, SUM(b) FROM t1 GROUP BY aa; SELECT a+CAST(1 AS decimal(65,31)) AS aa, SUM(b) FROM t1 GROUP BY aa;
ERROR 42000: Too big scale 31 specified for column '1'. Maximum is 30. ERROR 42000: Too big scale 31 specified for column '1'. Maximum is 30.
DROP TABLE t1; DROP TABLE t1;
@ -1521,13 +1521,13 @@ f1
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1; CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1;
Warnings: Warnings:
Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1
DESC t1; DESC t1;
Field Type Null Key Default Extra Field Type Null Key Default Extra
f1 decimal(65,20) NO 0.00000000000000000000 f1 decimal(65,30) NO 0.000000000000000000000000000000
SELECT f1 FROM t1; SELECT f1 FROM t1;
f1 f1
123451234512345123451234512345123451234512345.67890678906789067891 99999999999999999999999999999999999.999999999999999999999999999999
DROP TABLE t1; DROP TABLE t1;
select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 * select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
1.01500000 * 1.01500000 * 0.99500000); 1.01500000 * 1.01500000 * 0.99500000);
@ -1595,7 +1595,7 @@ Warnings:
Note 1265 Data truncated for column 'my_col' at row 1 Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1; DESCRIBE t1;
Field Type Null Key Default Extra Field Type Null Key Default Extra
my_col decimal(32,30) NO 0.000000000000000000000000000000 my_col decimal(65,30) NO 0.000000000000000000000000000000
SELECT my_col FROM t1; SELECT my_col FROM t1;
my_col my_col
1.123456789123456789123456789123 1.123456789123456789123456789123
@ -1625,212 +1625,8 @@ Warnings:
Note 1265 Data truncated for column 'my_col' at row 1 Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1; DESCRIBE t1;
Field Type Null Key Default Extra Field Type Null Key Default Extra
my_col decimal(30,30) YES NULL my_col decimal(65,30) YES NULL
SELECT my_col FROM t1; SELECT my_col FROM t1;
my_col my_col
0.012345687012345687012345687012 0.012345687012345687012345687012
DROP TABLE t1; 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;
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,25) NO 0.0000000000000000000000000
SELECT * FROM t1;
c1
1000000000000000000000000000000000000001.1000000000000000000000000
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:
Note 1265 Data truncated for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,20) NO 0.00000000000000000000
SELECT * FROM t1;
c1
123456789012345678901234567890123456789012345.12345678901234567890
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */
AS c1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,0) NO 0
SELECT * FROM t1;
c1
12345678901234567890123456789012345678901234567890123456789012345
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,0) NO 0
SELECT * FROM t1;
c1
99999999999999999999999999999999999999999999999999999999999999999
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,29) NO 0.00000000000000000000000000000
SELECT * FROM t1;
c1
2.10000000000000000000000000000
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(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 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(31,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;

View File

@ -19,6 +19,7 @@ DROP TABLE IF EXISTS tmp2, t;
SELECT GET_LOCK("a",10); SELECT GET_LOCK("a",10);
GET_LOCK("a",10) GET_LOCK("a",10)
1 1
USE test;
SELECT GET_LOCK("a",10); SELECT GET_LOCK("a",10);
GET_LOCK("a",10) GET_LOCK("a",10)
1 1

View File

@ -19,6 +19,7 @@ DROP TABLE IF EXISTS tmp2, t;
SELECT GET_LOCK("a",10); SELECT GET_LOCK("a",10);
GET_LOCK("a",10) GET_LOCK("a",10)
1 1
USE test;
SELECT GET_LOCK("a",10); SELECT GET_LOCK("a",10);
GET_LOCK("a",10) GET_LOCK("a",10)
1 1

View File

@ -728,3 +728,69 @@ where
from t4, t5 limit 2)); from t4, t5 limit 2));
drop table t0, t1, t2, t3, t4, t5; drop table t0, t1, t2, t3, t4, t5;
--echo #
--echo # BUG#48177 - SELECTs with NOT IN subqueries containing NULL
--echo # values return too many records
--echo #
CREATE TABLE t1 (
i1 int DEFAULT NULL,
i2 int DEFAULT NULL
) ;
INSERT INTO t1 VALUES (1, NULL);
INSERT INTO t1 VALUES (2, 3);
INSERT INTO t1 VALUES (4, NULL);
INSERT INTO t1 VALUES (4, 0);
INSERT INTO t1 VALUES (NULL, NULL);
CREATE TABLE t2 (
i1 int DEFAULT NULL,
i2 int DEFAULT NULL
) ;
INSERT INTO t2 VALUES (4, NULL);
INSERT INTO t2 VALUES (5, 0);
--echo
--echo Data in t1
SELECT i1, i2 FROM t1;
--echo
--echo Data in subquery (should be filtered out)
SELECT i1, i2 FROM t2 ORDER BY i1;
FLUSH STATUS;
--echo
SELECT i1, i2
FROM t1
WHERE (i1, i2)
NOT IN (SELECT i1, i2 FROM t2);
--echo
--echo # Check that the subquery only has to be evaluated once
--echo # for all-NULL values even though there are two (NULL,NULL) records
--echo # Baseline:
SHOW STATUS LIKE '%Handler_read_rnd_next';
--echo
INSERT INTO t1 VALUES (NULL, NULL);
FLUSH STATUS;
--echo
SELECT i1, i2
FROM t1
WHERE (i1, i2)
NOT IN (SELECT i1, i2 FROM t2);
--echo
--echo # Handler_read_rnd_next should be one more than baseline
--echo # (read record from t1, but do not read from t2)
SHOW STATUS LIKE '%Handler_read_rnd_next';
DROP TABLE t1,t2;
--echo End of 5.1 tests

View File

@ -1286,137 +1286,3 @@ CREATE TABLE t1 SELECT 1 % .1234567891234567891234567891234567891234567891234567
DESCRIBE t1; DESCRIBE t1;
SELECT my_col FROM t1; SELECT my_col FROM t1;
DROP TABLE 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;

View File

@ -2480,97 +2480,12 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg,
{ {
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg); precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
set_if_smaller(precision, DECIMAL_MAX_PRECISION); set_if_smaller(precision, DECIMAL_MAX_PRECISION);
DBUG_ASSERT(precision >= dec);
DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) && DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
(dec <= DECIMAL_MAX_SCALE)); (dec <= DECIMAL_MAX_SCALE));
bin_size= my_decimal_get_binary_size(precision, dec); bin_size= my_decimal_get_binary_size(precision, dec);
} }
/**
Create a field to hold a decimal value from an item.
@remark The MySQL DECIMAL data type has a characteristic that needs to be
taken into account when deducing the type from a Item_decimal.
But first, let's briefly recap what is the new MySQL DECIMAL type:
The declaration syntax for a decimal is DECIMAL(M,D), where:
* M is the maximum number of digits (the precision).
It has a range of 1 to 65.
* D is the number of digits to the right of the decimal separator (the scale).
It has a range of 0 to 30 and must be no larger than M.
D and M are used to determine the storage requirements for the integer
and fractional parts of each value. The integer part is to the left of
the decimal separator and to the right is the fractional part. Hence:
M is the number of digits for the integer and fractional part.
D is the number of digits for the fractional part.
Consequently, M - D is the number of digits for the integer part. For
example, a DECIMAL(20,10) column has ten digits on either side of
the decimal separator.
The characteristic that needs to be taken into account is that the
backing type for Item_decimal is a my_decimal that has a higher
precision (DECIMAL_MAX_POSSIBLE_PRECISION, see my_decimal.h) than
DECIMAL.
Drawing a comparison between my_decimal and DECIMAL:
* M has a range of 1 to 81.
* D has a range of 0 to 81.
There can be a difference in range if the decimal contains a integer
part. This is because the fractional part must always be on a group
boundary, leaving at least one group for the integer part. Since each
group is 9 (DIG_PER_DEC1) digits and there are 9 (DECIMAL_BUFF_LENGTH)
groups, the fractional part is limited to 72 digits if there is at
least one digit in the integral part.
Although the backing type for a DECIMAL is also my_decimal, every
time a my_decimal is stored in a DECIMAL field, the precision and
scale are explicitly capped at 65 (DECIMAL_MAX_PRECISION) and 30
(DECIMAL_MAX_SCALE) digits, following my_decimal truncation procedure
(FIX_INTG_FRAC_ERROR).
*/
Field_new_decimal *
Field_new_decimal::new_decimal_field(const Item *item)
{
uint32 len;
uint intg= item->decimal_int_part(), scale= item->decimals;
DBUG_ASSERT(item->decimal_precision() >= item->decimals);
/*
Employ a procedure along the lines of the my_decimal truncation process:
- If the integer part is equal to or bigger than the maximum precision:
Truncate integer part to fit and the fractional becomes zero.
- Otherwise:
Truncate fractional part to fit.
*/
if (intg >= DECIMAL_MAX_PRECISION)
{
intg= DECIMAL_MAX_PRECISION;
scale= 0;
}
else
{
uint room= min(DECIMAL_MAX_PRECISION - intg, DECIMAL_MAX_SCALE);
if (scale > room)
scale= room;
}
len= my_decimal_precision_to_length(intg + scale, scale, item->unsigned_flag);
return new Field_new_decimal(len, item->maybe_null, item->name, scale,
item->unsigned_flag);
}
int Field_new_decimal::reset(void) int Field_new_decimal::reset(void)
{ {
store_value(&decimal_zero); store_value(&decimal_zero);

View File

@ -621,10 +621,6 @@ protected:
class Field_num :public Field { class Field_num :public Field {
public: public:
/**
The scale of the Field's value, i.e. the number of digits to the right
of the decimal point.
*/
const uint8 dec; const uint8 dec;
bool zerofill,unsigned_flag; // Purify cannot handle bit fields bool zerofill,unsigned_flag; // Purify cannot handle bit fields
Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
@ -782,11 +778,6 @@ public:
Field_new_decimal(uint32 len_arg, bool maybe_null_arg, Field_new_decimal(uint32 len_arg, bool maybe_null_arg,
const char *field_name_arg, uint8 dec_arg, const char *field_name_arg, uint8 dec_arg,
bool unsigned_arg); bool unsigned_arg);
/*
Create a field to hold a decimal value from an item.
Truncates the precision and/or scale if necessary.
*/
static Field_new_decimal *new_decimal_field(const Item *item);
enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
Item_result result_type () const { return DECIMAL_RESULT; } Item_result result_type () const { return DECIMAL_RESULT; }

View File

@ -435,26 +435,17 @@ Item::Item(THD *thd, Item *item):
} }
/**
Decimal precision of the item.
@remark The precision must not be capped as it can be used in conjunction
with Item::decimals to determine the size of the integer part when
constructing a decimal data type.
@see Item::decimal_int_part()
@see Item::decimals
*/
uint Item::decimal_precision() const uint Item::decimal_precision() const
{ {
uint precision= max_length;
Item_result restype= result_type(); Item_result restype= result_type();
if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
precision= my_decimal_length_to_precision(max_length, decimals, unsigned_flag); {
uint prec=
return precision; my_decimal_length_to_precision(max_length, decimals, unsigned_flag);
return min(prec, DECIMAL_MAX_PRECISION);
}
return min(max_length, DECIMAL_MAX_PRECISION);
} }
@ -4908,7 +4899,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
switch (field_type()) { switch (field_type()) {
case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL: case MYSQL_TYPE_NEWDECIMAL:
field= Field_new_decimal::new_decimal_field(this); field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0,
Field::NONE, name, decimals, 0,
unsigned_flag);
break; break;
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,

View File

@ -762,10 +762,9 @@ public:
virtual cond_result eq_cmp_result() const { return COND_OK; } virtual cond_result eq_cmp_result() const { return COND_OK; }
inline uint float_length(uint decimals_par) const inline uint float_length(uint decimals_par) const
{ return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
/** Returns the uncapped decimal precision of this item. */
virtual uint decimal_precision() const; virtual uint decimal_precision() const;
inline int decimal_int_part() const inline int decimal_int_part() const
{ return decimal_precision() - decimals; } { return my_decimal_int_part(decimal_precision(), decimals); }
/* /*
Returns true if this is constant (during query execution, i.e. its value Returns true if this is constant (during query execution, i.e. its value
will not change until next fix_fields) and its value is known. will not change until next fix_fields) and its value is known.

View File

@ -1585,61 +1585,73 @@ longlong Item_in_optimizer::val_int()
if (cache->null_value) if (cache->null_value)
{ {
/*
We're evaluating
"<outer_value_list> [NOT] IN (SELECT <inner_value_list>...)"
where one or more of the outer values is NULL.
*/
if (((Item_in_subselect*)args[1])->is_top_level_item()) if (((Item_in_subselect*)args[1])->is_top_level_item())
{ {
/* /*
We're evaluating "NULL IN (SELECT ...)". The result can be NULL or We're evaluating a top level item, e.g.
FALSE, and we can return one instead of another. Just return NULL. "<outer_value_list> IN (SELECT <inner_value_list>...)",
and in this case a NULL value in the outer_value_list means
that the result shall be NULL/FALSE (makes no difference for
top level items). The cached value is NULL, so just return
NULL.
*/ */
null_value= 1; null_value= 1;
} }
else else
{ {
if (!((Item_in_subselect*)args[1])->is_correlated && /*
result_for_null_param != UNKNOWN) We're evaluating an item where a NULL value in either the
outer or inner value list does not automatically mean that we
can return NULL/FALSE. An example of such a query is
"<outer_value_list> NOT IN (SELECT <inner_value_list>...)"
The result when there is at least one NULL value is: NULL if the
SELECT evaluated over the non-NULL values produces at least
one row, FALSE otherwise
*/
Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
bool all_left_cols_null= true;
const uint ncols= cache->cols();
/*
Turn off the predicates that are based on column compares for
which the left part is currently NULL
*/
for (uint i= 0; i < ncols; i++)
{ {
/* Use cached value from previous execution */ if (cache->element_index(i)->null_value)
null_value= result_for_null_param; item_subs->set_cond_guard_var(i, FALSE);
else
all_left_cols_null= false;
} }
else
if (!((Item_in_subselect*)args[1])->is_correlated &&
all_left_cols_null && result_for_null_param != UNKNOWN)
{ {
/* /*
We're evaluating "NULL IN (SELECT ...)". The result is: This is a non-correlated subquery, all values in the outer
FALSE if SELECT produces an empty set, or value list are NULL, and we have already evaluated the
NULL otherwise. subquery for all NULL values: Return the same result we
We disable the predicates we've pushed down into subselect, run the did last time without evaluating the subquery.
subselect and see if it has produced any rows.
*/ */
Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; null_value= result_for_null_param;
if (cache->cols() == 1) }
{ else
item_subs->set_cond_guard_var(0, FALSE); {
(void) args[1]->val_bool_result(); /* The subquery has to be evaluated */
result_for_null_param= null_value= !item_subs->engine->no_rows(); (void) args[1]->val_bool_result();
item_subs->set_cond_guard_var(0, TRUE); null_value= !item_subs->engine->no_rows();
} if (all_left_cols_null)
else result_for_null_param= null_value;
{
uint i;
uint ncols= cache->cols();
/*
Turn off the predicates that are based on column compares for
which the left part is currently NULL
*/
for (i= 0; i < ncols; i++)
{
if (cache->element_index(i)->null_value)
item_subs->set_cond_guard_var(i, FALSE);
}
(void) args[1]->val_bool_result();
result_for_null_param= null_value= !item_subs->engine->no_rows();
/* Turn all predicates back on */
for (i= 0; i < ncols; i++)
item_subs->set_cond_guard_var(i, TRUE);
}
} }
/* Turn all predicates back on */
for (uint i= 0; i < ncols; i++)
item_subs->set_cond_guard_var(i, TRUE);
} }
return 0; return 0;
} }
@ -2217,7 +2229,7 @@ uint Item_func_ifnull::decimal_precision() const
int arg1_int_part= args[1]->decimal_int_part(); int arg1_int_part= args[1]->decimal_int_part();
int max_int_part= max(arg0_int_part, arg1_int_part); int max_int_part= max(arg0_int_part, arg1_int_part);
int precision= max_int_part + decimals; int precision= max_int_part + decimals;
return precision; return min(precision, DECIMAL_MAX_PRECISION);
} }
@ -2401,7 +2413,7 @@ uint Item_func_if::decimal_precision() const
int arg1_prec= args[1]->decimal_int_part(); int arg1_prec= args[1]->decimal_int_part();
int arg2_prec= args[2]->decimal_int_part(); int arg2_prec= args[2]->decimal_int_part();
int precision=max(arg1_prec,arg2_prec) + decimals; int precision=max(arg1_prec,arg2_prec) + decimals;
return precision; return min(precision, DECIMAL_MAX_PRECISION);
} }
@ -2809,7 +2821,7 @@ uint Item_func_case::decimal_precision() const
if (else_expr_num != -1) if (else_expr_num != -1)
set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part()); set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part());
return max_int_part + decimals; return min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
} }

View File

@ -451,8 +451,45 @@ Field *Item_func::tmp_table_field(TABLE *table)
return make_string_field(table); return make_string_field(table);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
field= Field_new_decimal::new_decimal_field(this); {
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);
break; break;
}
case ROW_RESULT: case ROW_RESULT:
default: default:
// This case should never be chosen // This case should never be chosen
@ -4739,19 +4776,6 @@ void Item_func_get_user_var::fix_length_and_dec()
} }
uint Item_func_get_user_var::decimal_precision() const
{
uint precision= max_length;
Item_result restype= result_type();
/* Default to maximum as the precision is unknown a priori. */
if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
precision= DECIMAL_MAX_PRECISION;
return precision;
}
bool Item_func_get_user_var::const_item() const bool Item_func_get_user_var::const_item() const
{ {
return (!var_entry || current_thd->query_id != var_entry->update_query_id); return (!var_entry || current_thd->query_id != var_entry->update_query_id);

View File

@ -1393,7 +1393,6 @@ public:
table_map used_tables() const table_map used_tables() const
{ return const_item() ? 0 : RAND_TABLE_BIT; } { return const_item() ? 0 : RAND_TABLE_BIT; }
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
uint decimal_precision() const;
private: private:
bool set_value(THD *thd, sp_rcontext *ctx, Item **it); bool set_value(THD *thd, sp_rcontext *ctx, Item **it);

View File

@ -517,7 +517,8 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
name, table->s, collation.collation); name, table->s, collation.collation);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
field= Field_new_decimal::new_decimal_field(this); field= new Field_new_decimal(max_length, maybe_null, name,
decimals, unsigned_flag);
break; break;
case ROW_RESULT: case ROW_RESULT:
default: default:

View File

@ -48,12 +48,10 @@ C_MODE_END
digits * number of decimal digits in one our big digit - number of decimal digits * number of decimal digits in one our big digit - number of decimal
digits in one our big digit decreased by 1 (because we always put decimal digits in one our big digit decreased by 1 (because we always put decimal
point on the border of our big digits)) point on the border of our big digits))
This value is 65 due to historical reasons partly due to it being used
as the maximum allowed precision and not the actual maximum precision.
*/ */
#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2) #define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
#define DECIMAL_MAX_SCALE 30 #define DECIMAL_MAX_SCALE 30
#define DECIMAL_NOT_SPECIFIED 31
/** /**
maximum length of string representation (number of maximum decimal maximum length of string representation (number of maximum decimal
@ -77,6 +75,12 @@ inline uint my_decimal_size(uint precision, uint scale)
} }
inline int my_decimal_int_part(uint precision, uint decimals)
{
return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals);
}
/** /**
my_decimal class limits 'decimal_t' type to what we need in MySQL. my_decimal class limits 'decimal_t' type to what we need in MySQL.
@ -180,7 +184,7 @@ inline uint my_decimal_length_to_precision(uint length, uint scale,
} }
inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
uint scale, uint8 scale,
bool unsigned_flag) bool unsigned_flag)
{ {
/* /*
@ -192,7 +196,7 @@ inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
(unsigned_flag || !precision ? 0 : 1)); (unsigned_flag || !precision ? 0 : 1));
} }
inline uint32 my_decimal_precision_to_length(uint precision, uint scale, inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
bool unsigned_flag) bool unsigned_flag)
{ {
/* /*

View File

@ -1548,6 +1548,7 @@ void close_temporary_tables(THD *thd)
s_query.length() - 1 /* to remove trailing ',' */, s_query.length() - 1 /* to remove trailing ',' */,
0, FALSE, 0); 0, FALSE, 0);
qinfo.db= db.ptr(); qinfo.db= db.ptr();
qinfo.db_len= db.length();
thd->variables.character_set_client= cs_save; thd->variables.character_set_client= cs_save;
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
thd->variables.pseudo_thread_id= save_pseudo_thread_id; thd->variables.pseudo_thread_id= save_pseudo_thread_id;

View File

@ -9436,8 +9436,47 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
new_field->set_derivation(item->collation.derivation); new_field->set_derivation(item->collation.derivation);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
new_field= Field_new_decimal::new_decimal_field(item); {
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);
break; break;
}
case ROW_RESULT: case ROW_RESULT:
default: default:
// This case should never be choosen // This case should never be choosen