From 511b9432637510617b04bde92c51a184c1e3aea8 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 10 Mar 2013 23:08:05 +0400 Subject: [PATCH 01/15] MDEV-4252 geometry query crashes server. The bug was found by Alyssa Milburn. If the number of points of a geometry feature read from binary representation is greater than 0x10000000, then the (uint32) (num_points * 16) will cut the higher byte, which leads to various errors. Fixed by additional check if (num_points > max_n_points). --- mysql-test/r/gis.result | 3 +++ mysql-test/t/gis.test | 1 + sql/spatial.cc | 27 ++++++++++++++++++--------- sql/spatial.h | 9 +++++---- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 8dad72fd3f8..69e73d018c7 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1087,4 +1087,7 @@ NULL # SELECT GEOMETRYCOLLECTION((SELECT @@OLD)); ERROR 22007: Illegal non geometric '' value found during parsing +select astext(0x0100000000030000000100000000000010); +astext(0x0100000000030000000100000000000010) +NULL End of 5.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index abda3e997bd..cc5d158f600 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -826,5 +826,6 @@ SELECT ISCLOSED(CONVERT(CONCAT(' ', 0x2), BINARY(20))); --error ER_ILLEGAL_VALUE_FOR_TYPE SELECT GEOMETRYCOLLECTION((SELECT @@OLD)); +select astext(0x0100000000030000000100000000000010); --echo End of 5.1 tests diff --git a/sql/spatial.cc b/sql/spatial.cc index eec028eaef1..94d0238993c 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -556,7 +556,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const n_points= uint4korr(data); data += 4; - if (n_points < 1 || + if (n_points < 1 || n_points > max_n_points || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) || txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points)) return 1; @@ -594,7 +594,8 @@ int Gis_line_string::geom_length(double *len) const return 1; n_points= uint4korr(data); data+= 4; - if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) + if (n_points < 1 || n_points > max_n_points || + no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) return 1; get_point(&prev_x, &prev_y, data); @@ -628,7 +629,7 @@ int Gis_line_string::is_closed(int *closed) const return 0; } data+= 4; - if (n_points == 0 || + if (n_points == 0 || n_points > max_n_points || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) return 1; @@ -798,7 +799,8 @@ bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const return 1; n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) || + if (n_points > max_n_points || + no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); @@ -852,7 +854,8 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const if (no_data(data, 4)) return 1; n_points= uint4korr(data); - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) + if (n_points > max_n_points || + no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; get_point(&prev_x, &prev_y, data+4); data+= (4+SIZEOF_STORED_DOUBLE*2); @@ -888,7 +891,8 @@ int Gis_polygon::exterior_ring(String *result) const n_points= uint4korr(data); data+= 4; length= n_points * POINT_DATA_SIZE; - if (no_data(data, length) || result->reserve(1+4+4+ length)) + if (n_points > max_n_points || + no_data(data, length) || result->reserve(1+4+4+ length)) return 1; result->q_append((char) wkb_ndr); @@ -973,7 +977,8 @@ int Gis_polygon::centroid_xy(double *x, double *y) const return 1; org_n_points= n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) + if (n_points > max_n_points || + no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; get_point(&prev_x, &prev_y, data); data+= (SIZEOF_STORED_DOUBLE*2); @@ -1260,7 +1265,8 @@ bool Gis_multi_line_string::get_data_as_wkt(String *txt, return 1; n_points= uint4korr(data + WKB_HEADER_SIZE); data+= WKB_HEADER_SIZE + 4; - if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) || + if (n_points > max_n_points || + no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); @@ -1521,7 +1527,8 @@ bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const return 1; uint32 n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) || + if (n_points > max_n_points || + no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points, 512)) return 1; @@ -1604,6 +1611,8 @@ int Gis_multi_polygon::geometry_n(uint32 num, String *result) const if (no_data(data, 4)) return 1; n_points= uint4korr(data); + if (n_points > max_n_points) + return 1; data+= 4 + POINT_DATA_SIZE * n_points; } } while (--num); diff --git a/sql/spatial.h b/sql/spatial.h index 20b3856ca9a..7d254252b3f 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -196,6 +196,11 @@ struct Geometry_buffer; class Geometry { +public: + // Maximum number of points in feature that can fit into String + static const uint32 max_n_points= + (uint32) (UINT_MAX32 - WKB_HEADER_SIZE - 4 /* n_points */) / + POINT_DATA_SIZE; public: Geometry() {} /* Remove gcc warning */ virtual ~Geometry() {} /* Remove gcc warning */ @@ -379,10 +384,6 @@ public: class Gis_line_string: public Geometry { - // Maximum number of points in LineString that can fit into String - static const uint32 max_n_points= - (uint32) (UINT_MAX32 - WKB_HEADER_SIZE - 4 /* n_points */) / - POINT_DATA_SIZE; public: Gis_line_string() {} /* Remove gcc warning */ virtual ~Gis_line_string() {} /* Remove gcc warning */ From 019f7425b70bb992bf6446a3c9a1dda041a4440d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 17 Mar 2013 07:41:22 +0100 Subject: [PATCH 02/15] MDEV-4281 Assertion `maybe_null && item->null_value' fails in make_sortkey on CASE with different return types, GROUP_CONCAT, GROUP BY Fix Item::get_date() to mark the item NULL when returning an error. --- mysql-test/r/cast.result | 20 ++++++++++---------- mysql-test/r/date_formats.result | 2 +- mysql-test/r/func_sapdb.result | 4 ++-- mysql-test/r/func_time.result | 7 +++---- mysql-test/r/partition_pruning.result | 3 ++- mysql-test/r/type_date.result | 2 +- mysql-test/r/type_datetime.result | 17 ++++++++++++++++- mysql-test/t/type_datetime.test | 11 +++++++++++ sql/filesort.cc | 5 ++++- sql/item.cc | 8 ++++++-- 10 files changed, 56 insertions(+), 23 deletions(-) diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 37550ce77f2..72e6dca8890 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -268,37 +268,37 @@ cast(010203101112.121314 as datetime) 0001-02-03 10:11:12 select cast(120010203101112.121314 as datetime); cast(120010203101112.121314 as datetime) -NULL +0000-00-00 00:00:00 Warnings: Warning 1292 Incorrect datetime value: '120010203101112.121314' select cast(cast(1.1 as decimal) as datetime); cast(cast(1.1 as decimal) as datetime) -NULL +0000-00-00 00:00:00 Warnings: Warning 1292 Incorrect datetime value: '1' select cast(cast(-1.1 as decimal) as datetime); cast(cast(-1.1 as decimal) as datetime) -NULL +0000-00-00 00:00:00 Warnings: Warning 1292 Incorrect datetime value: '-1' select cast('0' as date); cast('0' as date) -NULL +0000-00-00 Warnings: Warning 1292 Incorrect datetime value: '0' select cast('' as date); cast('' as date) -NULL +0000-00-00 Warnings: Warning 1292 Incorrect datetime value: '' select cast('0' as datetime); cast('0' as datetime) -NULL +0000-00-00 00:00:00 Warnings: Warning 1292 Incorrect datetime value: '0' select cast('' as datetime); cast('' as datetime) -NULL +0000-00-00 00:00:00 Warnings: Warning 1292 Incorrect datetime value: '' select cast('0' as time); @@ -306,7 +306,7 @@ cast('0' as time) 00:00:00 select cast('' as time); cast('' as time) -NULL +00:00:00 Warnings: Warning 1292 Truncated incorrect time value: '' select cast(NULL as DATE); @@ -323,13 +323,13 @@ cast(NULL as BINARY) NULL select cast(cast(120010203101112.121314 as double) as datetime); cast(cast(120010203101112.121314 as double) as datetime) -NULL +0000-00-00 00:00:00 select cast(cast(1.1 as double) as datetime); cast(cast(1.1 as double) as datetime) 0000-00-00 00:00:01 select cast(cast(-1.1 as double) as datetime); cast(cast(-1.1 as double) as datetime) -NULL +0000-00-00 00:00:00 explain extended select cast(10 as double(5,2)); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index dd346cb94dc..044338e98b8 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -586,7 +586,7 @@ TIME_FORMAT("25:00:00", '%l %p') 1 AM SELECT DATE_FORMAT('%Y-%m-%d %H:%i:%s', 1151414896); DATE_FORMAT('%Y-%m-%d %H:%i:%s', 1151414896) -NULL +1151414896 Warnings: Warning 1292 Incorrect datetime value: '%Y-%m-%d %H:%i:%s' select str_to_date('04 /30/2004', '%m /%d/%Y'); diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index f0c1abd84fe..5bd3b3f8fda 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -168,7 +168,7 @@ date("1997-12-31 23:59:59.000001") 1997-12-31 select date("1997-13-31 23:59:59.000001"); date("1997-13-31 23:59:59.000001") -NULL +0000-00-00 Warnings: Warning 1292 Incorrect datetime value: '1997-13-31 23:59:59.000001' select time("1997-12-31 23:59:59.000001"); @@ -176,7 +176,7 @@ time("1997-12-31 23:59:59.000001") 23:59:59.000001 select time("1997-12-31 25:59:59.000001"); time("1997-12-31 25:59:59.000001") -NULL +00:00:00 Warnings: Warning 1292 Truncated incorrect time value: '1997-12-31 25:59:59.000001' select microsecond("1997-12-31 23:59:59.000001"); diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 14d2729e952..c2e287be046 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -946,7 +946,6 @@ select f1 from t1 where cast("2006-1-1" as date) between f1 and cast('zzz' as da f1 Warnings: Warning 1292 Incorrect datetime value: 'zzz' -Warning 1292 Incorrect datetime value: 'zzz' select f1 from t1 where makedate(2006,1) between date(f1) and date(f3); f1 2006-01-01 @@ -1756,7 +1755,7 @@ Warnings: Warning 1441 Datetime function: time field overflow select cast('131415.123e0' as time); cast('131415.123e0' as time) -NULL +00:00:00 Warnings: Warning 1292 Truncated incorrect time value: '131415.123e0' select cast('2010-01-02 03:04:05' as datetime) between null and '2010-01-02 03:04:04'; @@ -1776,12 +1775,12 @@ unix_timestamp(null) NULL select truncate(date('2010-40-10'), 6); truncate(date('2010-40-10'), 6) -NULL +0.000000 Warnings: Warning 1292 Incorrect datetime value: '2010-40-10' select extract(month from '2010-40-50'); extract(month from '2010-40-50') -NULL +0 Warnings: Warning 1292 Incorrect datetime value: '2010-40-50' select subtime('0000-00-10 10:10:10', '30 10:00:00'); diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index d5594c7453e..f60c87aa351 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -1906,9 +1906,10 @@ INSERT INTO t1 VALUES (1, '2009-01-01'), (2, NULL); # test with an invalid date, which lead to item->null_value is set. EXPLAIN PARTITIONS SELECT * FROM t1 WHERE b < CAST('2009-04-99' AS DATETIME); id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +1 SIMPLE t1 p20090401 ALL NULL NULL NULL NULL 2 Using where Warnings: Warning 1292 Incorrect datetime value: '2009-04-99' +Warning 1292 Incorrect datetime value: '2009-04-99' DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index 23de0607838..8f9e692d3e0 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -136,7 +136,7 @@ select @d:=1311; 1311 select year(@d), month(@d), day(@d), cast(@d as date); year(@d) month(@d) day(@d) cast(@d as date) -NULL NULL NULL NULL +0 0 0 0000-00-00 Warnings: Warning 1292 Incorrect datetime value: '1311' Warning 1292 Incorrect datetime value: '1311' diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 1a111fe591a..1019462cdb5 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -573,7 +573,7 @@ CAST('NULL' AS DATE) < CAST('2008-01-01' AS DATE) n7, CAST('2008-01-01' AS DATE) < CAST('NULL' AS DATE) n8, CAST('NULL' AS DATE) < CAST('NULL' AS DATE) n9; n1 n2 n3 n4 n5 n6 n7 n8 n9 -0 0 1 NULL NULL NULL NULL NULL NULL +0 0 1 1 1 0 1 0 0 Warnings: Warning 1292 Incorrect datetime value: 'NULL' Warning 1292 Incorrect datetime value: 'NULL' @@ -585,6 +585,8 @@ Warning 1292 Incorrect datetime value: 'NULL' Warning 1292 Incorrect datetime value: 'NULL' Warning 1292 Incorrect datetime value: 'NULL' Warning 1292 Incorrect datetime value: 'NULL' +Warning 1292 Incorrect datetime value: 'NULL' +Warning 1292 Incorrect datetime value: 'NULL' End of 5.0 tests set @org_mode=@@sql_mode; create table t1 (da date default '1962-03-03 23:33:34', dt datetime default '1962-03-03'); @@ -651,3 +653,16 @@ SELECT * FROM t1; dt1 DROP TABLE t1; End of 5.1 tests +create table t1 (d date, t time) engine=myisam; +insert into t1 values ('2000-12-03','22:55:23'),('2008-05-03','10:19:31'); +select case when d = '2012-12-12' then d else t end as cond, group_concat( d ) from t1 group by cond; +cond group_concat( d ) +0000-00-00 00:00:00 2000-12-03 +0000-00-00 00:00:00 2008-05-03 +Warnings: +Warning 1292 Incorrect datetime value: '22:55:23' +Warning 1292 Incorrect datetime value: '10:19:31' +Warning 1292 Incorrect datetime value: '22:55:23' +Warning 1292 Incorrect datetime value: '10:19:31' +drop table t1; +End of 5.3 tests diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index f9ee8dfd5d3..eeba0ca69e3 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -462,3 +462,14 @@ SELECT * FROM t1; DROP TABLE t1; --echo End of 5.1 tests + +# +# MDEV-4281 Assertion `maybe_null && item->null_value' fails in make_sortkey on CASE with different return types, GROUP_CONCAT, GROUP BY +# +create table t1 (d date, t time) engine=myisam; +insert into t1 values ('2000-12-03','22:55:23'),('2008-05-03','10:19:31'); +select case when d = '2012-12-12' then d else t end as cond, group_concat( d ) from t1 group by cond; +drop table t1; + +--echo End of 5.3 tests + diff --git a/sql/filesort.cc b/sql/filesort.cc index 703264b7ef5..6619989c1ea 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -869,7 +869,10 @@ static void make_sortkey(register SORTPARAM *param, { MYSQL_TIME buf; if (item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES)) - DBUG_ASSERT(maybe_null && item->null_value); + { + DBUG_ASSERT(maybe_null); + DBUG_ASSERT(item->null_value); + } else value= pack_time(&buf); } diff --git a/sql/item.cc b/sql/item.cc index 2e023168f34..cb60d6fb812 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1197,11 +1197,15 @@ bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate) DBUG_ASSERT(0); } - return 0; + return null_value= 0; err: + /* + if the item was not null and convertion failed, we return a zero date + if allowed, otherwise - null. + */ bzero((char*) ltime,sizeof(*ltime)); - return 1; + return null_value|= (fuzzydate & (TIME_NO_ZERO_DATE|TIME_NO_ZERO_IN_DATE)); } bool Item::get_seconds(ulonglong *sec, ulong *sec_part) From 3827d70a0edb9b88f30dd64a2d7ee2853524dd4e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 17 Mar 2013 17:44:15 +0100 Subject: [PATCH 03/15] MDEV-4286 Server crashes in Protocol_text::store, stack smashing detected AVG() returns a double, its max_length is reasonably limited by a double number length, even if the argument is many Kbytes long. --- mysql-test/r/func_group.result | 7 +++++++ mysql-test/t/func_group.test | 8 ++++++++ sql/item_sum.cc | 5 +++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 10450b54781..bd77f800f67 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -2090,3 +2090,10 @@ set @@optimizer_switch=@save_optimizer_switch; # Cleanup for BUG#46680 # DROP TABLE IF EXISTS t1,t2,t3,empty1; +create table t1 (i int, d date); +insert into t1 values (1, '2008-10-02'), (2, '2010-12-12'); +select avg(export_set( 3, 'y', sha(i))), group_concat(d) from t1 group by d order by i; +avg(export_set( 3, 'y', sha(i))) group_concat(d) +0 2008-10-02 +0 2010-12-12 +drop table t1; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 3e31c61ac37..fef4d3b1de2 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1372,3 +1372,11 @@ set @@optimizer_switch=@save_optimizer_switch; --echo # DROP TABLE IF EXISTS t1,t2,t3,empty1; +# +# MDEV-4286 Server crashes in Protocol_text::store, stack smashing detected +# +create table t1 (i int, d date); +insert into t1 values (1, '2008-10-02'), (2, '2010-12-12'); +select avg(export_set( 3, 'y', sha(i))), group_concat(d) from t1 group by d order by i; +drop table t1; + diff --git a/sql/item_sum.cc b/sql/item_sum.cc index b9c041c1a2e..3f2020efeb5 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1242,9 +1242,10 @@ void Item_sum_avg::fix_length_and_dec() f_scale= args[0]->decimals; dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale); } - else { + else + { decimals= min(args[0]->decimals + prec_increment, NOT_FIXED_DEC); - max_length= args[0]->max_length + prec_increment; + max_length= min(args[0]->max_length + prec_increment, float_length(decimals)); } } From 8f607aae127439e132dae00b2750727162f4d564 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 Mar 2013 08:44:24 +0100 Subject: [PATCH 04/15] MDEV-4283 Assertion `scale <= precision' fails in strings/decimal.c with decimals=NOT_FIXED_DEC it is possible to have 'decimals' larger than 'max_length', it's not an error for temporal functions. But when Item_func_numhybrid converts the value to DECIMAL_RESULT, it must limit 'decimals' to be a valid scale of a decimal number. --- mysql-test/r/temporal_scale_4283.result | 12 ++++++++++++ mysql-test/t/temporal_scale_4283.test | 13 +++++++++++++ sql/item_func.cc | 4 +++- sql/item_func.h | 7 +++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/temporal_scale_4283.result create mode 100644 mysql-test/t/temporal_scale_4283.test diff --git a/mysql-test/r/temporal_scale_4283.result b/mysql-test/r/temporal_scale_4283.result new file mode 100644 index 00000000000..685a6192a97 --- /dev/null +++ b/mysql-test/r/temporal_scale_4283.result @@ -0,0 +1,12 @@ +create table t1 (a int); +insert into t1 values (4),(8); +select distinct 100 mod timestampadd( week, a, '2002-05-20' ) from t1; +100 mod timestampadd( week, a, '2002-05-20' ) +100 +drop table t1; +create table t1 (i int); +insert into t1 values (2),(4); +select distinct convert_tz( '2001-03-21', 'utc', 'met' ) mod i from t1; +convert_tz( '2001-03-21', 'utc', 'met' ) mod i +0 +drop table t1; diff --git a/mysql-test/t/temporal_scale_4283.test b/mysql-test/t/temporal_scale_4283.test new file mode 100644 index 00000000000..d79ca7caa54 --- /dev/null +++ b/mysql-test/t/temporal_scale_4283.test @@ -0,0 +1,13 @@ +# +# MDEV-4283 Assertion `scale <= precision' fails in strings/decimal.c +# +create table t1 (a int); +insert into t1 values (4),(8); +select distinct 100 mod timestampadd( week, a, '2002-05-20' ) from t1; +drop table t1; + +create table t1 (i int); +insert into t1 values (2),(4); +select distinct convert_tz( '2001-03-21', 'utc', 'met' ) mod i from t1; +drop table t1; + diff --git a/sql/item_func.cc b/sql/item_func.cc index f3a5c08d621..120e3d73a34 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -742,13 +742,14 @@ void Item_num_op::find_num_type(void) { hybrid_type= DECIMAL_RESULT; result_precision(); + fix_decimals(); } else { DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT); - decimals= 0; hybrid_type=INT_RESULT; result_precision(); + decimals= 0; } DBUG_PRINT("info", ("Type: %s", (hybrid_type == REAL_RESULT ? "REAL_RESULT" : @@ -1492,6 +1493,7 @@ void Item_func_div::fix_length_and_dec() break; case DECIMAL_RESULT: result_precision(); + fix_decimals(); break; case STRING_RESULT: case ROW_RESULT: diff --git a/sql/item_func.h b/sql/item_func.h index 2db8ab76ffe..6cd036920f8 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -348,6 +348,13 @@ public: void fix_num_length_and_dec(); virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */ + inline void fix_decimals() + { + DBUG_ASSERT(result_type() == DECIMAL_RESULT); + if (decimals == NOT_FIXED_DEC) + set_if_smaller(decimals, max_length - 1); + } + double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); From a4a18e0cbbaf2a43507b3c2232fed700403ad04d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 Mar 2013 10:35:03 +0100 Subject: [PATCH 05/15] MDEV-4289 Assertion `0' fails in make_sortkey with GROUP_CONCAT, MAKE_SET, GROUP BY Item_func_make_set wasn't taking into account the first argument when calculating maybe_null. sql/item_strfunc.cc: rewrite Item_func_make_set, removing separate storage of the first argument sql/item_strfunc.h: rewrite Item_func_make_set, removing separate storage of the first argument --- mysql-test/r/func_str.result | 7 ++++ mysql-test/t/func_str.test | 7 ++++ sql/item_create.cc | 3 +- sql/item_strfunc.cc | 72 ++++-------------------------------- sql/item_strfunc.h | 20 +--------- 5 files changed, 24 insertions(+), 85 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index aef452b7b50..db2c3430784 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2646,4 +2646,11 @@ NULL SELECT LPAD('hi', DAY(FROM_UNIXTIME(-1)),'?'); LPAD('hi', DAY(FROM_UNIXTIME(-1)),'?') NULL +create table t1 (i int); +insert into t1 values (null),(8); +select group_concat( i ), make_set( i, 'a', 'b' ) field from t1 group by field; +group_concat( i ) field +NULL NULL +8 +drop table t1; End of 5.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 9909974d3be..f49fa633925 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1390,5 +1390,12 @@ SELECT REPEAT('1', DAY(FROM_UNIXTIME(-1))); SELECT RPAD('hi', DAY(FROM_UNIXTIME(-1)),'?'); SELECT LPAD('hi', DAY(FROM_UNIXTIME(-1)),'?'); +# +# MDEV-4289 Assertion `0' fails in make_sortkey with GROUP_CONCAT, MAKE_SET, GROUP BY +# +create table t1 (i int); +insert into t1 values (null),(8); +select group_concat( i ), make_set( i, 'a', 'b' ) field from t1 group by field; +drop table t1; --echo End of 5.1 tests diff --git a/sql/item_create.cc b/sql/item_create.cc index a5dc3eeb5ad..78b50ff01fc 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -3952,8 +3952,7 @@ Create_func_make_set::create_native(THD *thd, LEX_STRING name, return NULL; } - Item *param_1= item_list->pop(); - return new (thd->mem_root) Item_func_make_set(param_1, *item_list); + return new (thd->mem_root) Item_func_make_set(*item_list); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 9cc77849094..ffa227834a9 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2233,37 +2233,14 @@ String *Item_func_elt::val_str(String *str) } -void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array, - List &fields) -{ - item->split_sum_func2(thd, ref_pointer_array, fields, &item, TRUE); - Item_str_func::split_sum_func(thd, ref_pointer_array, fields); -} - - void Item_func_make_set::fix_length_and_dec() { - max_length=arg_count-1; - - if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV, 1)) + if (agg_arg_charsets(collation, args+1, arg_count-1, MY_COLL_ALLOW_CONV, 1)) return; - for (uint i=0 ; i < arg_count ; i++) + max_length=arg_count-2; + for (uint i=1 ; i < arg_count ; i++) max_length+=args[i]->max_length; - - used_tables_cache|= item->used_tables(); - not_null_tables_cache&= item->not_null_tables(); - const_item_cache&= item->const_item(); - with_sum_func= with_sum_func || item->with_sum_func; -} - - -void Item_func_make_set::update_used_tables() -{ - Item_func::update_used_tables(); - item->update_used_tables(); - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); } @@ -2272,15 +2249,15 @@ String *Item_func_make_set::val_str(String *str) DBUG_ASSERT(fixed == 1); ulonglong bits; bool first_found=0; - Item **ptr=args; + Item **ptr=args+1; String *result=&my_empty_string; - bits=item->val_int(); - if ((null_value=item->null_value)) + bits=args[0]->val_int(); + if ((null_value=args[0]->null_value)) return NULL; - if (arg_count < 64) - bits &= ((ulonglong) 1 << arg_count)-1; + if (arg_count < 65) + bits &= ((ulonglong) 1 << (arg_count-1))-1; for (; bits; bits >>= 1, ptr++) { @@ -2320,39 +2297,6 @@ String *Item_func_make_set::val_str(String *str) } -Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg) -{ - DBUG_ASSERT(!current_thd->is_stmt_prepare()); - - Item *new_item= item->transform(transformer, arg); - if (!new_item) - return 0; - - /* - THD::change_item_tree() should be called only if the tree was - really transformed, i.e. when a new item has been created. - Otherwise we'll be allocating a lot of unnecessary memory for - change records at each execution. - */ - if (item != new_item) - current_thd->change_item_tree(&item, new_item); - return Item_str_func::transform(transformer, arg); -} - - -void Item_func_make_set::print(String *str, enum_query_type query_type) -{ - str->append(STRING_WITH_LEN("make_set(")); - item->print(str, query_type); - if (arg_count) - { - str->append(','); - print_args(str, 0, query_type); - } - str->append(')'); -} - - String *Item_func_char::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index e8fa041af4f..a4fae7c69a1 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -497,31 +497,13 @@ public: class Item_func_make_set :public Item_str_func { - Item *item; String tmp_str; public: - Item_func_make_set(Item *a,List &list) :Item_str_func(list),item(a) {} + Item_func_make_set(List &list) :Item_str_func(list) {} String *val_str(String *str); - bool fix_fields(THD *thd, Item **ref) - { - DBUG_ASSERT(fixed == 0); - return ((!item->fixed && item->fix_fields(thd, &item)) || - item->check_cols(1) || - Item_func::fix_fields(thd, ref)); - } - void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); void fix_length_and_dec(); - void update_used_tables(); const char *func_name() const { return "make_set"; } - - bool walk(Item_processor processor, bool walk_subquery, uchar *arg) - { - return item->walk(processor, walk_subquery, arg) || - Item_str_func::walk(processor, walk_subquery, arg); - } - Item *transform(Item_transformer transformer, uchar *arg); - virtual void print(String *str, enum_query_type query_type); }; From 589247ae86b25eaa9bd75e4f26ecd06831469311 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 18 Mar 2013 17:58:00 +0400 Subject: [PATCH 06/15] MDEV-4252 geometry query crashes server. Additional fixes for possible overflows in length-related calculations in 'spatial' implementations. Checks added to the ::get_data_size() methods. max_n_points decreased to occupy less 2G size. An object of that size is practically inoperable anyway. --- mysql-test/r/gis.result | 12 ++++++++ mysql-test/t/gis.test | 6 ++++ sql/spatial.cc | 67 +++++++++++++++++++++++++++++------------ sql/spatial.h | 2 +- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 69e73d018c7..7566f0beb8c 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1087,7 +1087,19 @@ NULL # SELECT GEOMETRYCOLLECTION((SELECT @@OLD)); ERROR 22007: Illegal non geometric '' value found during parsing +# +# MDEV-4252 geometry query crashes server +# select astext(0x0100000000030000000100000000000010); astext(0x0100000000030000000100000000000010) NULL +select envelope(0x0100000000030000000100000000000010); +envelope(0x0100000000030000000100000000000010) +NULL +select geometryn(0x0100000000070000000100000001030000000200000000000000ffff0000, 1); +geometryn(0x0100000000070000000100000001030000000200000000000000ffff0000, 1) +NULL +select geometryn(0x0100000000070000000100000001030000000200000000000000ffffff0f, 1); +geometryn(0x0100000000070000000100000001030000000200000000000000ffffff0f, 1) +NULL End of 5.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index cc5d158f600..c42541e82b8 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -826,6 +826,12 @@ SELECT ISCLOSED(CONVERT(CONCAT(' ', 0x2), BINARY(20))); --error ER_ILLEGAL_VALUE_FOR_TYPE SELECT GEOMETRYCOLLECTION((SELECT @@OLD)); +--echo # +--echo # MDEV-4252 geometry query crashes server +--echo # select astext(0x0100000000030000000100000000000010); +select envelope(0x0100000000030000000100000000000010); +select geometryn(0x0100000000070000000100000001030000000200000000000000ffff0000, 1); +select geometryn(0x0100000000070000000100000001030000000200000000000000ffffff0f, 1); --echo End of 5.1 tests diff --git a/sql/spatial.cc b/sql/spatial.cc index 94d0238993c..5a4b768140c 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -394,18 +394,19 @@ const char *Geometry::append_points(String *txt, uint32 n_points, const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, uint offset) const { - uint32 points; + uint32 n_points; /* read number of points */ if (no_data(data, 4)) return 0; - points= uint4korr(data); + n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points)) + if (n_points > max_n_points || + no_data(data, (POINT_DATA_SIZE + offset) * n_points)) return 0; /* Calculate MBR for points */ - while (points--) + while (n_points--) { data+= offset; mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE); @@ -484,9 +485,12 @@ const Geometry::Class_info *Gis_point::get_class_info() const uint32 Gis_line_string::get_data_size() const { - if (no_data(m_data, 4)) + uint32 n_points, size; + if (no_data(m_data, 4) || + (n_points= uint4korr(m_data)) > max_n_points || + no_data(m_data, (size= 4 + n_points * POINT_DATA_SIZE))) return GET_SIZE_ERROR; - return 4 + uint4korr(m_data) * POINT_DATA_SIZE; + return size; } @@ -665,6 +669,9 @@ int Gis_line_string::end_point(String *result) const if (no_data(m_data, 4)) return 1; n_points= uint4korr(m_data); + if (n_points == 0 || n_points > max_n_points || + no_data(m_data, POINT_DATA_SIZE * n_points)) + return 1; return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE); } @@ -674,11 +681,14 @@ int Gis_line_string::point_n(uint32 num, String *result) const uint32 n_points; if (no_data(m_data, 4)) return 1; + num--; n_points= uint4korr(m_data); - if ((uint32) (num - 1) >= n_points) // means (num > n_points || num < 1) + if (num >= n_points || + num > max_n_points || // means (num > n_points || num < 1) + no_data(m_data, num * POINT_DATA_SIZE)) return 1; - return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE); + return create_point(result, m_data + 4 + num*POINT_DATA_SIZE); } const Geometry::Class_info *Gis_line_string::get_class_info() const @@ -692,6 +702,7 @@ const Geometry::Class_info *Gis_line_string::get_class_info() const uint32 Gis_polygon::get_data_size() const { uint32 n_linear_rings; + uint32 n_points; const char *data= m_data; if (no_data(data, 4)) @@ -701,10 +712,13 @@ uint32 Gis_polygon::get_data_size() const while (n_linear_rings--) { - if (no_data(data, 4)) + if (no_data(data, 4) || + (n_points= uint4korr(data)) > max_n_points) return GET_SIZE_ERROR; - data+= 4 + uint4korr(data)*POINT_DATA_SIZE; + data+= 4 + n_points*POINT_DATA_SIZE; } + if (no_data(data, 0)) + return GET_SIZE_ERROR; return (uint32) (data - m_data); } @@ -1037,9 +1051,14 @@ const Geometry::Class_info *Gis_polygon::get_class_info() const uint32 Gis_multi_point::get_data_size() const { - if (no_data(m_data, 4)) - return GET_SIZE_ERROR; - return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE); + uint32 n_points; + uint32 size; + + if (no_data(m_data, 4) || + (n_points= uint4korr(m_data)) > max_n_points || + no_data(m_data, (size= 4 + n_points*(POINT_DATA_SIZE + WKB_HEADER_SIZE)))) + return GET_SIZE_ERROR; + return size; } @@ -1107,7 +1126,8 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const return 1; n_points= uint4korr(m_data); - if (no_data(m_data+4, + if (n_points > max_n_points || + no_data(m_data+4, n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) || txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; @@ -1160,6 +1180,7 @@ const Geometry::Class_info *Gis_multi_point::get_class_info() const uint32 Gis_multi_line_string::get_data_size() const { uint32 n_line_strings; + uint32 n_points; const char *data= m_data; if (no_data(data, 4)) @@ -1169,11 +1190,13 @@ uint32 Gis_multi_line_string::get_data_size() const while (n_line_strings--) { - if (no_data(data, WKB_HEADER_SIZE + 4)) + if (no_data(data, WKB_HEADER_SIZE + 4) || + (n_points= uint4korr(data + WKB_HEADER_SIZE)) > max_n_points) return GET_SIZE_ERROR; - data+= (WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) * - POINT_DATA_SIZE); + data+= (WKB_HEADER_SIZE + 4 + n_points*POINT_DATA_SIZE); } + if (no_data(data, 0)) + return GET_SIZE_ERROR; return (uint32) (data - m_data); } @@ -1327,7 +1350,7 @@ int Gis_multi_line_string::geometry_n(uint32 num, String *result) const return 1; n_points= uint4korr(data + WKB_HEADER_SIZE); length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points; - if (no_data(data, length)) + if (n_points > max_n_points || no_data(data, length)) return 1; if (!--num) break; @@ -1407,6 +1430,7 @@ const Geometry::Class_info *Gis_multi_line_string::get_class_info() const uint32 Gis_multi_polygon::get_data_size() const { uint32 n_polygons; + uint32 n_points; const char *data= m_data; if (no_data(data, 4)) @@ -1425,11 +1449,14 @@ uint32 Gis_multi_polygon::get_data_size() const while (n_linear_rings--) { - if (no_data(data, 4)) + if (no_data(data, 4) || + (n_points= uint4korr(data)) > max_n_points) return GET_SIZE_ERROR; - data+= 4 + uint4korr(data) * POINT_DATA_SIZE; + data+= 4 + n_points * POINT_DATA_SIZE; } } + if (no_data(data, 0)) + return GET_SIZE_ERROR; return (uint32) (data - m_data); } diff --git a/sql/spatial.h b/sql/spatial.h index 7d254252b3f..d7632c11143 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -199,7 +199,7 @@ class Geometry public: // Maximum number of points in feature that can fit into String static const uint32 max_n_points= - (uint32) (UINT_MAX32 - WKB_HEADER_SIZE - 4 /* n_points */) / + (uint32) (INT_MAX32 - WKB_HEADER_SIZE - 4 /* n_points */) / POINT_DATA_SIZE; public: Geometry() {} /* Remove gcc warning */ From 2cd7cf8fe6fa41fca124c9239468fc22f8df9957 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 18 Mar 2013 15:07:52 +0200 Subject: [PATCH 07/15] MDEV-4269 fix. Item_default_value inherited form Item_field so should create temporary table field similary. --- mysql-test/r/func_group_innodb.result | 14 ++++++++++++++ mysql-test/t/func_group_innodb.test | 14 ++++++++++++++ sql/sql_select.cc | 1 + 3 files changed, 29 insertions(+) diff --git a/mysql-test/r/func_group_innodb.result b/mysql-test/r/func_group_innodb.result index e68242a8191..9d64b63f8f0 100644 --- a/mysql-test/r/func_group_innodb.result +++ b/mysql-test/r/func_group_innodb.result @@ -185,3 +185,17 @@ member_id_to COUNT(*) 518491 5 DROP TABLE t1; # End of test BUG#12713907 +# +# MDEV-4269: crash when grouping by values() +# +SELECT @@storage_engine INTO @old_engine; +set storage_engine=innodb; +create table y select 1 b; +select 1 from y group by b; +1 +1 +select 1 from y group by values(b); +1 +1 +drop table y; +SET storage_engine=@old_engine; diff --git a/mysql-test/t/func_group_innodb.test b/mysql-test/t/func_group_innodb.test index 58f365bb244..accd1f6a6b5 100644 --- a/mysql-test/t/func_group_innodb.test +++ b/mysql-test/t/func_group_innodb.test @@ -127,3 +127,17 @@ SELECT member_id_to, COUNT(*) FROM t1 WHERE r_date = DROP TABLE t1; --echo # End of test BUG#12713907 + +--echo # +--echo # MDEV-4269: crash when grouping by values() +--echo # + +SELECT @@storage_engine INTO @old_engine; +set storage_engine=innodb; + +create table y select 1 b; +select 1 from y group by b; +select 1 from y group by values(b); +drop table y; +SET storage_engine=@old_engine; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bc8b7a9e815..24ca1ab0174 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9922,6 +9922,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, } case Item::FIELD_ITEM: case Item::DEFAULT_VALUE_ITEM: + case Item::INSERT_VALUE_ITEM: { Item_field *field= (Item_field*) item; bool orig_modify= modify_item; From 15a7335d77d056e860a9fdc844343c840e310e68 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 19 Mar 2013 17:16:10 +0400 Subject: [PATCH 08/15] MDEV-4296 Assertion `n_linear_rings > 0' fails in Gis_polygon::centroid_xy. Forgotten DBUG_ASSERT should be replaced with the 'return error'. --- mysql-test/r/gis.result | 6 ++++++ mysql-test/t/gis.test | 5 +++++ sql/spatial.cc | 6 ++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 7566f0beb8c..6ea977d5bfd 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1102,4 +1102,10 @@ NULL select geometryn(0x0100000000070000000100000001030000000200000000000000ffffff0f, 1); geometryn(0x0100000000070000000100000001030000000200000000000000ffffff0f, 1) NULL +# +# MDEV-4296 Assertion `n_linear_rings > 0' fails in Gis_polygon::centroid_xy +# +SELECT Centroid( AsBinary( LineString(Point(0,0), Point(0,0), Point(0,0) ))); +Centroid( AsBinary( LineString(Point(0,0), Point(0,0), Point(0,0) ))) +NULL End of 5.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index c42541e82b8..b8cce077e3e 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -834,4 +834,9 @@ select envelope(0x0100000000030000000100000000000010); select geometryn(0x0100000000070000000100000001030000000200000000000000ffff0000, 1); select geometryn(0x0100000000070000000100000001030000000200000000000000ffffff0f, 1); +--echo # +--echo # MDEV-4296 Assertion `n_linear_rings > 0' fails in Gis_polygon::centroid_xy +--echo # + +SELECT Centroid( AsBinary( LineString(Point(0,0), Point(0,0), Point(0,0) ))); --echo End of 5.1 tests diff --git a/sql/spatial.cc b/sql/spatial.cc index 5a4b768140c..afaa67763e8 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -972,13 +972,11 @@ int Gis_polygon::centroid_xy(double *x, double *y) const const char *data= m_data; bool first_loop= 1; - if (no_data(data, 4)) + if (no_data(data, 4) || + (n_linear_rings= uint4korr(data)) == 0) return 1; - n_linear_rings= uint4korr(data); data+= 4; - DBUG_ASSERT(n_linear_rings > 0); - while (n_linear_rings--) { uint32 n_points, org_n_points; From ef737284b416292d21837d7dedbffe66a4b4b8d4 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 19 Mar 2013 17:25:58 +0400 Subject: [PATCH 09/15] MDEV-4295 Server crashes in get_point on a query with Area, AsBinary, MultiPoint. Need to check if the number of points is 0 for the polygon. --- mysql-test/r/gis.result | 6 ++++++ mysql-test/t/gis.test | 5 +++++ sql/spatial.cc | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 6ea977d5bfd..b6521636685 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1108,4 +1108,10 @@ NULL SELECT Centroid( AsBinary( LineString(Point(0,0), Point(0,0), Point(0,0) ))); Centroid( AsBinary( LineString(Point(0,0), Point(0,0), Point(0,0) ))) NULL +# +# MDEV-4295 Server crashes in get_point on a query with Area, AsBinary, MultiPoint +# +SELECT Area(AsBinary(MultiPoint(Point(0,9), Point(0,1), Point(2,2)))); +Area(AsBinary(MultiPoint(Point(0,9), Point(0,1), Point(2,2)))) +NULL End of 5.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index b8cce077e3e..698b9455da3 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -839,4 +839,9 @@ select geometryn(0x0100000000070000000100000001030000000200000000000000ffffff0f, --echo # SELECT Centroid( AsBinary( LineString(Point(0,0), Point(0,0), Point(0,0) ))); + +--echo # +--echo # MDEV-4295 Server crashes in get_point on a query with Area, AsBinary, MultiPoint +--echo # +SELECT Area(AsBinary(MultiPoint(Point(0,9), Point(0,1), Point(2,2)))); --echo End of 5.1 tests diff --git a/sql/spatial.cc b/sql/spatial.cc index afaa67763e8..52110960f96 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -868,7 +868,7 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const if (no_data(data, 4)) return 1; n_points= uint4korr(data); - if (n_points > max_n_points || + if (n_points == 0 || n_points > max_n_points || no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; get_point(&prev_x, &prev_y, data+4); @@ -989,7 +989,7 @@ int Gis_polygon::centroid_xy(double *x, double *y) const return 1; org_n_points= n_points= uint4korr(data); data+= 4; - if (n_points > max_n_points || + if (n_points == 0 || n_points > max_n_points || no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; get_point(&prev_x, &prev_y, data); From 1be429561723dc20ff7f4f1739eb0580cf70564b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 Mar 2013 16:13:00 +0100 Subject: [PATCH 10/15] MDEV-4293 Valgrind warnings (Conditional jump or move depends on uninitialised value) in remove_eq_conds on time functions with NULL argument val_int() is expected to return 0 for NULL's --- mysql-test/r/func_time.result | 12 ++++++++++++ mysql-test/t/func_time.test | 10 ++++++++++ sql/item_timefunc.cc | 18 ++++++------------ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index c2e287be046..3828af31991 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1898,3 +1898,15 @@ microsecond('12:00:00.123456') microsecond('2009-12-31 23:59:59.000010') 123456 10 select now(258); ERROR 42000: Too big precision 258 specified for 'now'. Maximum is 6. +SELECT 1 FROM DUAL WHERE YEAR(TIMEDIFF(NULL, '12:12:12')); +1 +SELECT 1 FROM DUAL WHERE MONTH(TIMEDIFF(NULL, '12:12:12')); +1 +SELECT 1 FROM DUAL WHERE DAYOFMONTH(TIMEDIFF(NULL, '12:12:12')); +1 +SELECT 1 FROM DUAL WHERE HOUR(TIMEDIFF(NULL, '12:12:12')); +1 +SELECT 1 FROM DUAL WHERE MINUTE(TIMEDIFF(NULL, '12:12:12')); +1 +SELECT 1 FROM DUAL WHERE SECOND(TIMEDIFF(NULL, '12:12:12')); +1 diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index c3d1d74ec50..c68b1260396 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1144,3 +1144,13 @@ select microsecond('12:00:00.123456'), microsecond('2009-12-31 23:59:59.000010') --error ER_TOO_BIG_PRECISION select now(258); + +# +# MDEV-4293 Valgrind warnings (Conditional jump or move depends on uninitialised value) in remove_eq_conds on time functions with NULL argument in WHERE +# +SELECT 1 FROM DUAL WHERE YEAR(TIMEDIFF(NULL, '12:12:12')); +SELECT 1 FROM DUAL WHERE MONTH(TIMEDIFF(NULL, '12:12:12')); +SELECT 1 FROM DUAL WHERE DAYOFMONTH(TIMEDIFF(NULL, '12:12:12')); +SELECT 1 FROM DUAL WHERE HOUR(TIMEDIFF(NULL, '12:12:12')); +SELECT 1 FROM DUAL WHERE MINUTE(TIMEDIFF(NULL, '12:12:12')); +SELECT 1 FROM DUAL WHERE SECOND(TIMEDIFF(NULL, '12:12:12')); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 9f2f9b2950d..a3b7611ba69 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -856,16 +856,14 @@ longlong Item_func_dayofmonth::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - (void) get_arg0_date(<ime, TIME_FUZZY_DATE); - return (longlong) ltime.day; + return get_arg0_date(<ime, TIME_FUZZY_DATE) ? 0 : (longlong) ltime.day; } longlong Item_func_month::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - (void) get_arg0_date(<ime, TIME_FUZZY_DATE); - return (longlong) ltime.month; + return get_arg0_date(<ime, TIME_FUZZY_DATE) ? 0 : (longlong) ltime.month; } @@ -919,16 +917,14 @@ longlong Item_func_hour::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - (void) get_arg0_time(<ime); - return ltime.hour; + return get_arg0_time(<ime) ? 0 : ltime.hour; } longlong Item_func_minute::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - (void) get_arg0_time(<ime); - return ltime.minute; + return get_arg0_time(<ime) ? 0 : ltime.minute; } /** @@ -938,8 +934,7 @@ longlong Item_func_second::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - (void) get_arg0_time(<ime); - return ltime.second; + return get_arg0_time(<ime) ? 0 : ltime.second; } @@ -1056,8 +1051,7 @@ longlong Item_func_year::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - (void) get_arg0_date(<ime, TIME_FUZZY_DATE); - return (longlong) ltime.year; + return get_arg0_date(<ime, TIME_FUZZY_DATE) ? 0 : (longlong) ltime.year; } From e70ce465b7f4daf7124f442c95425ad66b92b527 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 Mar 2013 21:20:51 +0100 Subject: [PATCH 11/15] add 'plugins' suite - empty, but the line ./mtr --suite=main,plugins will work on all branches. From fb2501e2d4cf099bfea0cc1ef9d441ad08c3ee68 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 21 Mar 2013 11:06:27 +0400 Subject: [PATCH 12/15] MDEV-4277: Crash inside mi_killed_in_mariadb() with myisammrg - Set MI_INFO::external_ref for MyISAM tables that are parts of myisamMRG table. --- mysql-test/r/merge.result | 130 ++++++++++++++++++++++++++++++ mysql-test/t/merge.test | 35 ++++++++ storage/myisammrg/ha_myisammrg.cc | 14 ++++ 3 files changed, 179 insertions(+) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 1e1e6aeaa6b..105a1f9f4c2 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2369,3 +2369,133 @@ ERROR HY000: Can't reopen table: 'm1' UNLOCK TABLES; DROP TABLE t1, t2, t3, m1; End of 5.1 tests +# +# MDEV-4277: Crash inside mi_killed_in_mariadb() with myisammrg +# +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 ( i int ) engine=myisam; +insert into t2 values (1),(2); +create table t3 (a int, b int, filler char(100), key(a), key(b)) engine=myisam; +create table t4 like t3; +insert into t3 +select A.a+10*B.a+100*C.a, +A.a+10*B.a+100*C.a, +'filler-data-FILLER-DATA-qqq' +from t1 A, t1 B, t1 C where C.a < 5; +insert into t4 +select A.a+10*B.a+100*C.a, +A.a+10*B.a+100*C.a, +'filler-data-FILLER-DATA-qqq' +from t1 A, t1 B, t1 C where C.a >= 5; +create table t5 like t3; +alter table t5 engine=merge; +alter table t5 union(t3, t4); +update t5 set b=999, a=999 where b>950; +explain +select * from t2, t5 where t5.a=999 and t5.b=999; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t5 index_merge a,b a,b 5,5 NULL 6 Using intersect(a,b); Using where; Using join buffer (flat, BNL join) +select * from t2, t5 where t5.a=999 and t5.b=999; +i a b filler +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +1 999 999 filler-data-FILLER-DATA-qqq +2 999 999 filler-data-FILLER-DATA-qqq +drop table t5; +drop table t1,t2,t3,t4; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index eecf892869f..abb7c3c7da2 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1865,6 +1865,41 @@ DROP TABLE t1, t2, t3, m1; --echo End of 5.1 tests +--echo # +--echo # MDEV-4277: Crash inside mi_killed_in_mariadb() with myisammrg +--echo # +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t2 ( i int ) engine=myisam; +insert into t2 values (1),(2); + +create table t3 (a int, b int, filler char(100), key(a), key(b)) engine=myisam; +create table t4 like t3; +insert into t3 + select A.a+10*B.a+100*C.a, + A.a+10*B.a+100*C.a, + 'filler-data-FILLER-DATA-qqq' + from t1 A, t1 B, t1 C where C.a < 5; +insert into t4 + select A.a+10*B.a+100*C.a, + A.a+10*B.a+100*C.a, + 'filler-data-FILLER-DATA-qqq' + from t1 A, t1 B, t1 C where C.a >= 5; + +create table t5 like t3; +alter table t5 engine=merge; +alter table t5 union(t3, t4); + +update t5 set b=999, a=999 where b>950; + +explain +select * from t2, t5 where t5.a=999 and t5.b=999; +select * from t2, t5 where t5.a=999 and t5.b=999; + +drop table t5; +drop table t1,t2,t3,t4; + --disable_result_log --disable_query_log eval set global storage_engine=$default; diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 274ba2fcd81..61fa32f86fe 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -422,6 +422,19 @@ static MI_INFO *myisammrg_attach_children_callback(void *callback_param) DBUG_RETURN(my_errno ? NULL : myisam); } +/* + Set external_ref for the child MyISAM tables. They need this to be set in + order to check for killed status. +*/ +static void myrg_set_external_ref(MYRG_INFO *m_info, void *ext_ref_arg) +{ + int i; + for (i= 0; i < (int)m_info->tables; i++) + { + m_info->open_tables[i].table->external_ref= ext_ref_arg; + } +} + /** @brief Open a MERGE parent table, not its children. @@ -467,6 +480,7 @@ int ha_myisammrg::open(const char *name, int mode __attribute__((unused)), } file->children_attached= TRUE; + myrg_set_external_ref(file, (void*)table); info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); } From 2b89b0a271fb9d32ad8a509bd8774a5059a8a480 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 22 Mar 2013 17:32:27 +0400 Subject: [PATCH 13/15] MDEV-4310 geometry function equals hangs forever. The Geometry::get_mbr() function can return an error on a bad data. We have to check for that and act respectively. --- mysql-test/r/gis.result | 41 +++++++++++++++++++++++++++++------------ mysql-test/t/gis.test | 10 ++++++++++ sql/item_geofunc.cc | 25 ++++++++++++------------- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index f29d096fc57..d84ec1d7480 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -406,20 +406,20 @@ FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second first second w c o e d t i r 120 120 1 1 0 1 0 1 1 0 120 121 0 0 1 0 0 0 1 0 -120 122 0 1 NULL 0 NULL 0 NULL 0 -120 123 0 1 NULL 0 NULL 0 NULL 0 +120 122 NULL NULL NULL NULL NULL NULL NULL NULL +120 123 NULL NULL NULL NULL NULL NULL NULL NULL 121 120 0 0 1 0 0 0 1 0 121 121 1 1 0 1 0 1 1 0 -121 122 0 1 NULL 0 NULL 0 NULL 0 -121 123 0 1 NULL 0 NULL 0 NULL 0 -122 120 1 0 NULL 0 NULL 0 NULL 0 -122 121 1 0 NULL 0 NULL 0 NULL 0 -122 122 1 1 NULL 1 NULL 0 NULL 0 -122 123 1 1 NULL 1 NULL 0 NULL 0 -123 120 1 0 NULL 0 NULL 0 NULL 0 -123 121 1 0 NULL 0 NULL 0 NULL 0 -123 122 1 1 NULL 1 NULL 0 NULL 0 -123 123 1 1 NULL 1 NULL 0 NULL 0 +121 122 NULL NULL NULL NULL NULL NULL NULL NULL +121 123 NULL NULL NULL NULL NULL NULL NULL NULL +122 120 NULL NULL NULL NULL NULL NULL NULL NULL +122 121 NULL NULL NULL NULL NULL NULL NULL NULL +122 122 NULL NULL NULL NULL NULL NULL NULL NULL +122 123 NULL NULL NULL NULL NULL NULL NULL NULL +123 120 NULL NULL NULL NULL NULL NULL NULL NULL +123 121 NULL NULL NULL NULL NULL NULL NULL NULL +123 122 NULL NULL NULL NULL NULL NULL NULL NULL +123 123 NULL NULL NULL NULL NULL NULL NULL NULL explain extended SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -1473,6 +1473,7 @@ WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; count(*) 1 DROP DATABASE gis_ogs; +USE test; # # BUG #1043845 st_distance() results are incorrect depending on variable order # @@ -1496,3 +1497,19 @@ geomfromtext('LINESTRING(-95.9673005697771 36.13509598461, -95.9673057475387 36.1344478941074, -95.9673063519371 36. 0.008148695928138 +# +# MDEV-4310 geometry function equals hangs forever. +# +create table t1(a geometry not null)engine=myisam; +insert into t1 values(geomfromtext("POINT(0 0)")); +insert into t1 values(geomfromtext("POINT(0 9.2233720368548e18)")); +insert into t1 values(geomfromtext("POINT(0 9.2233720368548e18)")); +select equals(`a`,convert(`a` using utf8)) from `t1`; +equals(`a`,convert(`a` using utf8)) +1 +NULL +NULL +Warnings: +Warning 1300 Invalid utf8 character string: 'E043' +Warning 1300 Invalid utf8 character string: 'E043' +drop table t1; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index cdbc253869e..6b4578c39c1 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -1355,6 +1355,7 @@ WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; #WHERE lakes.name = 'Blue Lake'; DROP DATABASE gis_ogs; +USE test; --echo # --echo # BUG #1043845 st_distance() results are incorrect depending on variable order @@ -1371,3 +1372,12 @@ select st_distance(geomfromtext('point(-95.96269500000000000000 36.1418183333333 -95.9673063519371 36.134484524621, -95.9673049102515 36.1343976584193) ')) ; +--echo # +--echo # MDEV-4310 geometry function equals hangs forever. +--echo # +create table t1(a geometry not null)engine=myisam; +insert into t1 values(geomfromtext("POINT(0 0)")); +insert into t1 values(geomfromtext("POINT(0 9.2233720368548e18)")); +insert into t1 values(geomfromtext("POINT(0 9.2233720368548e18)")); +select equals(`a`,convert(`a` using utf8)) from `t1`; +drop table t1; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index ba330ba3b96..7d0f06d6237 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -685,12 +685,11 @@ longlong Item_func_spatial_rel::val_int() if ((null_value= (args[0]->null_value || args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || - !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) + !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || + g1->get_mbr(&mbr1, &c_end) || + g2->get_mbr(&mbr2, &c_end)))) goto exit; - g1->get_mbr(&mbr1, &c_end); - g2->get_mbr(&mbr2, &c_end); - umbr= mbr1; umbr.add_mbr(&mbr2); collector.set_extent(umbr.xmin, umbr.xmax, umbr.ymin, umbr.ymax); @@ -824,14 +823,14 @@ String *Item_func_spatial_operation::val_str(String *str_value) if ((null_value= (args[0]->null_value || args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || - !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) + !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || + g1->get_mbr(&mbr1, &c_end) || + g2->get_mbr(&mbr2, &c_end)))) { str_value= 0; goto exit; } - g1->get_mbr(&mbr1, &c_end); - g2->get_mbr(&mbr2, &c_end); mbr1.add_mbr(&mbr2); collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax); @@ -1356,11 +1355,11 @@ longlong Item_func_issimple::val_int() DBUG_ENTER("Item_func_issimple::val_int"); DBUG_ASSERT(fixed == 1); - if ((null_value= args[0]->null_value) || - !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))) + if ((null_value= (args[0]->null_value || + !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) || + g->get_mbr(&mbr, &c_end)))) DBUG_RETURN(0); - g->get_mbr(&mbr, &c_end); collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); if (g->get_class_info()->m_type_id == Geometry::wkb_point) @@ -1596,11 +1595,11 @@ double Item_func_distance::val_real() if ((null_value= (args[0]->null_value || args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || - !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()))))) + !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || + g1->get_mbr(&mbr1, &c_end) || + g2->get_mbr(&mbr2, &c_end)))) goto mem_error; - g1->get_mbr(&mbr1, &c_end); - g2->get_mbr(&mbr2, &c_end); mbr1.add_mbr(&mbr2); collector.set_extent(mbr1.xmin, mbr1.xmax, mbr1.ymin, mbr1.ymax); From 51a707486433d3707ac38deb72c6ad7d3d7bb882 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Mar 2013 13:07:46 +0200 Subject: [PATCH 14/15] MDEV-4292 fix. Fixed printing column_get finction. --- mysql-test/r/dyncol.result | 91 +++++++++++++++++++++++++++++++++----- mysql-test/t/dyncol.test | 57 ++++++++++++++++++++++++ sql/item_strfunc.cc | 7 ++- 3 files changed, 144 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/dyncol.result b/mysql-test/r/dyncol.result index d38660adcc6..6b1dd4d96ec 100644 --- a/mysql-test/r/dyncol.result +++ b/mysql-test/r/dyncol.result @@ -182,13 +182,13 @@ select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212 AS unsigned int),1) as unsigned) AS `column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int)` +Note 1003 select column_get(column_create(1,1212 AS unsigned int),1 as unsigned) AS `column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int)` explain extended select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212 AS unsigned int),1) as unsigned) AS `column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned)` +Note 1003 select column_get(column_create(1,1212 AS unsigned int),1 as unsigned) AS `column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned)` select column_get(column_create(1, 1212 AS decimal), 1 as unsigned int); column_get(column_create(1, 1212 AS decimal), 1 as unsigned int) 1212 @@ -261,13 +261,13 @@ select column_get(column_create(1, 1212 AS int), 1 as int); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212 AS int),1) as signed) AS `column_get(column_create(1, 1212 AS int), 1 as int)` +Note 1003 select column_get(column_create(1,1212 AS int),1 as signed) AS `column_get(column_create(1, 1212 AS int), 1 as int)` explain extended select column_get(column_create(1, 1212 AS int), 1 as signed int); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212 AS int),1) as signed) AS `column_get(column_create(1, 1212 AS int), 1 as signed int)` +Note 1003 select column_get(column_create(1,1212 AS int),1 as signed) AS `column_get(column_create(1, 1212 AS int), 1 as signed int)` select column_get(column_create(1, -1212 AS int), 1 as int); column_get(column_create(1, -1212 AS int), 1 as int) -1212 @@ -368,7 +368,7 @@ select column_get(column_create(1, "1212" AS char charset utf8), 1 as char chars id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,'1212' AS char charset utf8 ),1) as char charset utf8) AS `column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8)` +Note 1003 select column_get(column_create(1,'1212' AS char charset utf8 ),1 as char charset utf8) AS `column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8)` select column_get(column_create(1, 1212 AS unsigned int), 1 as char charset utf8); column_get(column_create(1, 1212 AS unsigned int), 1 as char charset utf8) 1212 @@ -428,7 +428,7 @@ select column_get(column_create(1, "1212" AS char charset utf8), 1 as char chars id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,'1212' AS char charset utf8 ),1) as char charset binary) AS `column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary)` +Note 1003 select column_get(column_create(1,'1212' AS char charset utf8 ),1 as char charset binary) AS `column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary)` # # column get real # @@ -440,13 +440,13 @@ select column_get(column_create(1, 1212.12 AS double), 1 as double); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212.12 AS double),1) as double) AS `column_get(column_create(1, 1212.12 AS double), 1 as double)` +Note 1003 select column_get(column_create(1,1212.12 AS double),1 as double) AS `column_get(column_create(1, 1212.12 AS double), 1 as double)` explain extended select column_get(column_create(1, 1212.12 AS double), 1 as double(6,2)); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212.12 AS double),1) as double(6,2)) AS `column_get(column_create(1, 1212.12 AS double), 1 as double(6,2))` +Note 1003 select column_get(column_create(1,1212.12 AS double),1 as double(6,2)) AS `column_get(column_create(1, 1212.12 AS double), 1 as double(6,2))` select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as double); column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as double) 1.84467440737096e+19 @@ -521,13 +521,13 @@ select column_get(column_create(1, 1212.12 AS double), 1 as decimal); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212.12 AS double),1) as decimal(10,0)) AS `column_get(column_create(1, 1212.12 AS double), 1 as decimal)` +Note 1003 select column_get(column_create(1,1212.12 AS double),1 as decimal(10,0)) AS `column_get(column_create(1, 1212.12 AS double), 1 as decimal)` explain extended select column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2)); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select cast(column_get(column_create(1,1212.12 AS double),1) as decimal(6,2)) AS `column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2))` +Note 1003 select column_get(column_create(1,1212.12 AS double),1 as decimal(6,2)) AS `column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2))` select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal(20,0)); column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal(20,0)) 18446744073709551615 @@ -1335,3 +1335,74 @@ hex(COLUMN_CREATE(0, COLUMN_GET(COLUMN_CREATE(0, 0.0 as decimal), 0 as decimal)) select hex(COLUMN_CREATE(0, 0.0 as decimal)); hex(COLUMN_CREATE(0, 0.0 as decimal)) 000100000004 +# +# MDEV-4292: parse error when selecting on views using dynamic column +# +create table t1 (i int, d blob); +create view v1 as select i, column_get(d, 1 as binary) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as char charset binary) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as int) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as signed) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as unsigned int) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as unsigned) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as date) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as date) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as time) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as time) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as datetime) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as datetime) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as decimal) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as decimal(10,0)) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as double) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as double) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +create view v1 as select i, column_get(d, 1 as char) as a from t1; +select * from v1; +i a +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i`,column_get(`t1`.`d`,1 as char charset latin1) AS `a` from `t1` latin1 latin1_swedish_ci +drop view v1; +drop table t1; +# +# end of 5.3 tests +# diff --git a/mysql-test/t/dyncol.test b/mysql-test/t/dyncol.test index 1901a998732..ca3ff600509 100644 --- a/mysql-test/t/dyncol.test +++ b/mysql-test/t/dyncol.test @@ -546,3 +546,60 @@ select hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL(19,0)))); select hex(COLUMN_CREATE(0, COLUMN_GET(COLUMN_CREATE(0, 0.0 as decimal), 0 as decimal))); select hex(COLUMN_CREATE(0, 0.0 as decimal)); + +--echo # +--echo # MDEV-4292: parse error when selecting on views using dynamic column +--echo # +create table t1 (i int, d blob); + +create view v1 as select i, column_get(d, 1 as binary) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as int) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as unsigned int) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as date) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as time) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as datetime) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as decimal) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as double) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +create view v1 as select i, column_get(d, 1 as char) as a from t1; +select * from v1; +show create view v1; +drop view v1; + +drop table t1; + +--echo # +--echo # end of 5.3 tests +--echo # + diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 71526c433ed..f8da7cc094c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -4246,11 +4246,16 @@ null: void Item_dyncol_get::print(String *str, enum_query_type query_type) { + /* see create_func_dyncol_get */ + DBUG_ASSERT(str->length() >= 5); + DBUG_ASSERT(strncmp(str->ptr() + str->length() - 5, "cast(", 5) == 0); + + str->length(str->length() - 5); // removing "cast(" str->append(STRING_WITH_LEN("column_get(")); args[0]->print(str, query_type); str->append(','); args[1]->print(str, query_type); - str->append(')'); + /* let the parent cast item add " as )" */ } From 045c498691f77ac8e0d8c8b9b705325b3425c69d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 26 Mar 2013 21:47:06 +0400 Subject: [PATCH 15/15] GEOMETRYCOLLECTION EMPTY handling fixed. The get_mbr() method shouldn't return the error, rather an invalid MBR in this case. --- sql/item_geofunc.cc | 12 ++++++------ sql/spatial.cc | 21 +++++++++++++++------ sql/spatial.h | 3 +++ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 7d0f06d6237..1168813e275 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -559,8 +559,8 @@ longlong Item_func_spatial_mbr_rel::val_int() args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || - g1->get_mbr(&mbr1, &dummy) || - g2->get_mbr(&mbr2, &dummy)))) + g1->get_mbr(&mbr1, &dummy) || !mbr1.valid() || + g2->get_mbr(&mbr2, &dummy) || !mbr2.valid()))) return 0; switch (spatial_rel) { @@ -686,8 +686,8 @@ longlong Item_func_spatial_rel::val_int() (args[0]->null_value || args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || - g1->get_mbr(&mbr1, &c_end) || - g2->get_mbr(&mbr2, &c_end)))) + g1->get_mbr(&mbr1, &c_end) || !mbr1.valid() || + g2->get_mbr(&mbr2, &c_end) || !mbr2.valid()))) goto exit; umbr= mbr1; @@ -824,8 +824,8 @@ String *Item_func_spatial_operation::val_str(String *str_value) (args[0]->null_value || args[1]->null_value || !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || - g1->get_mbr(&mbr1, &c_end) || - g2->get_mbr(&mbr2, &c_end)))) + g1->get_mbr(&mbr1, &c_end) || !mbr1.valid() || + g2->get_mbr(&mbr2, &c_end) || !mbr2.valid()))) { str_value= 0; goto exit; diff --git a/sql/spatial.cc b/sql/spatial.cc index 0da2fdf40b3..cec6150c22a 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -308,6 +308,9 @@ bool Geometry::envelope(String *result) const const char *end; if (get_mbr(&mbr, &end)) + return 1; + + if (!mbr.valid()) { /* Empty geometry */ if (result->reserve(1 + 4*2)) @@ -2322,7 +2325,7 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const n_objects= uint4korr(data); data+= 4; if (n_objects == 0) - return 1; + goto exit; while (n_objects--) { @@ -2339,6 +2342,7 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const if (geom->get_mbr(mbr, &data)) return 1; } +exit: *end= data; return 0; } @@ -2356,10 +2360,11 @@ int Gis_geometry_collection::area(double *ar, const char **end) const return 1; n_objects= uint4korr(data); data+= 4; - if (n_objects == 0) - return 1; result= 0.0; + if (n_objects == 0) + goto exit; + while (n_objects--) { uint32 wkb_type; @@ -2376,6 +2381,7 @@ int Gis_geometry_collection::area(double *ar, const char **end) const return 1; result+= *ar; } +exit: *end= data; *ar= result; return 0; @@ -2394,10 +2400,11 @@ int Gis_geometry_collection::geom_length(double *len, const char **end) const return 1; n_objects= uint4korr(data); data+= 4; - if (n_objects == 0) - return 1; - result= 0.0; + + if (n_objects == 0) + goto exit; + while (n_objects--) { uint32 wkb_type; @@ -2414,6 +2421,8 @@ int Gis_geometry_collection::geom_length(double *len, const char **end) const return 1; result+= *len; } + +exit: *end= data; *len= result; return 0; diff --git a/sql/spatial.h b/sql/spatial.h index 6850cc804d0..1108f5d5e50 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -199,6 +199,9 @@ struct MBR return (d == intersection.dimension()); } + + int valid() const + { return xmin <= xmax && ymin <= ymax; } };