From 2718aa5a29e8b29c5bb17f04bfafb092ddc0ab2a Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Wed, 25 Nov 2009 13:23:25 +0100 Subject: [PATCH 01/35] Set version number for mysql-5.1.40sp1 release --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 3e43a5f5779..1d123c96bc9 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.40) +AM_INIT_AUTOMAKE(mysql, 5.1.40sp1) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 From c7f31d41d422987668451978ba9d72e2c93e0a6a Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:32:04 +0100 Subject: [PATCH 02/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 1810.3959.4 > revision-id: ramil@mysql.com-20091021090408-208mvwwrcroi2j8c > parent: azundris@mysql.com-20091021033856-ydodp4q42o58e7ka > committer: Ramil Kalimullin > branch nick: b47019-5.0-bugteam > timestamp: Wed 2009-10-21 14:04:08 +0500 > message: > Fix for bug#47019: Assertion failed: 0, file .\rt_mbr.c, > line 138 when forcing a spatial index > > Problem: "Spatial indexes can be involved in the search > for queries that use a function such as MBRContains() > or MBRWithin() in the WHERE clause". > Using spatial indexes for JOINs with =, <=> etc. > predicates is incorrect. > > Fix: disable spatial indexes for such queries. --- mysql-test/r/select.result | 29 +++++++++++++++++++++++++++++ mysql-test/t/select.test | 16 ++++++++++++++++ sql/sql_select.cc | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 50b5c3c13fb..a41f95de077 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4386,6 +4386,35 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` > 1)) limit 2 DROP TABLE t1; +# +# Bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when +# forcing a spatial index +# +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL a NULL NULL NULL 2 +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +1 +1 +1 +1 +1 +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL a NULL NULL NULL 2 +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +1 +1 +1 +1 +1 +DROP TABLE t1; End of 5.0 tests create table t1(a INT, KEY (a)); INSERT INTO t1 VALUES (1),(2),(3),(4),(5); diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 7d3785ecccc..1e7e853da32 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3739,6 +3739,22 @@ EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND a = b LIMIT 2; EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND b = a LIMIT 2; DROP TABLE t1; + + +--echo # +--echo # Bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when +--echo # forcing a spatial index +--echo # +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3f1432914a0..79e7012346c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3539,7 +3539,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) { if (!(form->keys_in_use_for_query.is_set(key))) continue; - if (form->key_info[key].flags & HA_FULLTEXT) + if (form->key_info[key].flags & (HA_FULLTEXT | HA_SPATIAL)) continue; // ToDo: ft-keys in non-ft queries. SerG uint key_parts= (uint) form->key_info[key].key_parts; From c466f08328d93a118a46a860543ef312b83993c0 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:35:05 +0100 Subject: [PATCH 03/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 1810.3959.5 > revision-id: ramil@mysql.com-20091023112648-gie6o3odj57cxh1e > parent: ramil@mysql.com-20091021090408-208mvwwrcroi2j8c > committer: Ramil Kalimullin > branch nick: b48258-5.0-bugteam > timestamp: Fri 2009-10-23 16:26:48 +0500 > message: > Fix for bug#48258: Assertion failed when using a spatial index > > Problem: involving a spatial index for "non-spatial" queries > (that don't containt MBRXXX() functions) may lead to failed assert. > > Fix: don't use spatial indexes in such cases. --- mysql-test/r/gis-rtree.result | 39 +++++++++++++++++++++++++++++++++++ mysql-test/t/gis-rtree.test | 21 +++++++++++++++++++ sql/opt_range.cc | 21 +++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index b030139e40e..68c4a6a13e5 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -1487,4 +1487,43 @@ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') ); COUNT(*) 2 DROP TABLE t1; +# +# Bug #48258: Assertion failed when using a spatial index +# +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +1 +1 +EXPLAIN SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +EXPLAIN SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +1 +1 +EXPLAIN SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +EXPLAIN SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +1 +1 +DROP TABLE t1; End of 5.0 tests. diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index 19bbcf19cca..c325b3bd223 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -881,4 +881,25 @@ SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE DROP TABLE t1; + +--echo # +--echo # Bug #48258: Assertion failed when using a spatial index +--echo # +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +DROP TABLE t1; + + --echo End of 5.0 tests. diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 05575e2744b..68c70c915c3 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5709,6 +5709,27 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, !(conf_func->compare_collation()->state & MY_CS_BINSORT)) goto end; + if (key_part->image_type == Field::itMBR) + { + switch (type) { + case Item_func::SP_EQUALS_FUNC: + case Item_func::SP_DISJOINT_FUNC: + case Item_func::SP_INTERSECTS_FUNC: + case Item_func::SP_TOUCHES_FUNC: + case Item_func::SP_CROSSES_FUNC: + case Item_func::SP_WITHIN_FUNC: + case Item_func::SP_CONTAINS_FUNC: + case Item_func::SP_OVERLAPS_FUNC: + break; + default: + /* + We cannot involve spatial indexes for queries that + don't use MBREQUALS(), MBRDISJOINT(), etc. functions. + */ + goto end; + } + } + if (param->using_real_indexes) optimize_range= field->optimize_range(param->real_keynr[key_part->key], key_part->part); From e0f253147a28b26af84d14863af903044d7039c6 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:36:58 +0100 Subject: [PATCH 04/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 1810.3959.6 > revision-id: joro@sun.com-20091021084345-iki6z0uceieoupey > parent: ramil@mysql.com-20091023112648-gie6o3odj57cxh1e > committer: Georgi Kodinov > branch nick: B47780-5.0-bugteam > timestamp: Wed 2009-10-21 11:43:45 +0300 > message: > Bug #47780: crash when comparing GIS items from subquery > > If the first argument to GeomFromWKB function is a geometry > field then the function just returns its value. > However in doing so it's not preserving first argument's > null_value flag and this causes unexpected null value to > be returned to the calling function. > > Fixed by updating the null_value of the GeomFromWKB function > in such cases (and all other cases that return a NULL e.g. > because of not enough memory for the return buffer). --- mysql-test/r/gis.result | 12 ++++++++++++ mysql-test/t/gis.test | 16 ++++++++++++++++ sql/item_geofunc.cc | 9 +++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index a3708d06a1c..b40ff6be160 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -972,6 +972,18 @@ select min(`col002`) from t1 union select `col002` from t1; min(`col002`) NULL drop table t1; +# +# Bug #47780: crash when comparing GIS items from subquery +# +CREATE TABLE t1(a INT, b MULTIPOLYGON); +INSERT INTO t1 VALUES +(0, +GEOMFROMTEXT( +'multipolygon(((1 2,3 4,5 6,7 8,9 8),(7 6,5 4,3 2,1 2,3 4)))')); +# must not crash +SELECT 1 FROM t1 WHERE a <> (SELECT GEOMETRYCOLLECTIONFROMWKB(b) FROM t1); +1 +DROP TABLE t1; End of 5.0 tests create table t1 (f1 tinyint(1), f2 char(1), f3 varchar(1), f4 geometry, f5 datetime); create view v1 as select * from t1; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 4a60e777cc7..2d10c3bf1e1 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -655,6 +655,22 @@ insert into t1 values (),(),(); select min(`col002`) from t1 union select `col002` from t1; drop table t1; +--echo # +--echo # Bug #47780: crash when comparing GIS items from subquery +--echo # + +CREATE TABLE t1(a INT, b MULTIPOLYGON); +INSERT INTO t1 VALUES + (0, + GEOMFROMTEXT( + 'multipolygon(((1 2,3 4,5 6,7 8,9 8),(7 6,5 4,3 2,1 2,3 4)))')); + +--echo # must not crash +SELECT 1 FROM t1 WHERE a <> (SELECT GEOMETRYCOLLECTIONFROMWKB(b) FROM t1); + +DROP TABLE t1; + + --echo End of 5.0 tests diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index a34204b7181..3c5990eb359 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -84,7 +84,9 @@ String *Item_func_geometry_from_wkb::val_str(String *str) if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY) { - return args[0]->val_str(str); + String *str_ret= args[0]->val_str(str); + null_value= args[0]->null_value; + return str_ret; } wkb= args[0]->val_str(&arg_val); @@ -94,7 +96,10 @@ String *Item_func_geometry_from_wkb::val_str(String *str) str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) - return 0; + { + null_value= TRUE; /* purecov: inspected */ + return 0; /* purecov: inspected */ + } str->length(0); str->q_append(srid); if ((null_value= From d8798e2960437539de86d1392cc279b346643226 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:42:10 +0100 Subject: [PATCH 05/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 1810.3961.12 > revision-id: li-bing.song@sun.com-20091103090041-zj7nedx6ok5jgges > parent: davi.arnaut@sun.com-20091102201021-1brn7cjb1kvqg9gr > committer: > branch nick: mysql-5.0-bugteam > timestamp: Tue 2009-11-03 17:00:41 +0800 > message: > BUG#48216 Replication fails on all slaves after upgrade to 5.0.86 on master > > When a sessione is closed, all temporary tables of the session are automatically > dropped and are binlogged. But it will be binlogged with wrong database names when > the length of the temporary tables' database names are greater than the > length of the current database name or the current database is not set. > > Query_log_event's db_len is forgot to set when Query_log_event's db is set. > This patch wrote code to set db_len immediately after db has set. --- sql/sql_base.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d1e96fcdbb3..5225c15f319 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1547,6 +1547,7 @@ void close_temporary_tables(THD *thd) s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE, 0); qinfo.db= db.ptr(); + qinfo.db_len= db.length(); thd->variables.character_set_client= cs_save; mysql_bin_log.write(&qinfo); thd->variables.pseudo_thread_id= save_pseudo_thread_id; From 3ebac06ddb4ce5e7e92d5b1f89125827256c6ced Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:43:47 +0100 Subject: [PATCH 06/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 1810.3961.6 > revision-id: joro@sun.com-20091030094044-quadg0bwjy7cwqzw > parent: joro@sun.com-20091029152429-ks55fhrp4lhknyij > committer: Georgi Kodinov > branch nick: B48293-5.0-bugteam > timestamp: Fri 2009-10-30 11:40:44 +0200 > message: > Bug #48293: crash with procedure analyse, view with > 10 columns, > having clause... > > The fix for bug 46184 was not very complete. It was not covering > views using temporary tables and multiple tables in a FROM clause. > Fixed by reverting the fix for 46184 and making a more general > check that is checking at the right execution stage and for all > of the non-supported cases. > Now PROCEDURE ANALYZE on non-top level SELECT is also forbidden. > Updated the analyse.test and subselect.test accordingly. --- mysql-test/r/analyse.result | 112 ++++++++++++---------------------- mysql-test/r/subselect.result | 2 +- mysql-test/t/analyse.test | 70 +++++++++++++-------- mysql-test/t/subselect.test | 2 +- sql/sql_select.cc | 12 ++++ sql/sql_yacc.yy | 3 +- 6 files changed, 99 insertions(+), 102 deletions(-) diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index 6eaa8731dc6..1820782d2f8 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -19,81 +19,10 @@ test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL create table t2 select * from t1 procedure analyse(); -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -test.t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL -test.t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL -test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL -test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL -test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL -drop table t1,t2; +ERROR HY000: Incorrect usage of PROCEDURE and non-SELECT +drop table t1; EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); ERROR HY000: Incorrect usage of PROCEDURE and subquery -create table t1 (a int not null); -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `Field_name` varbinary(255) NOT NULL DEFAULT '', - `Min_value` varbinary(255) DEFAULT NULL, - `Max_value` varbinary(255) DEFAULT NULL, - `Min_length` bigint(11) NOT NULL DEFAULT '0', - `Max_length` bigint(11) NOT NULL DEFAULT '0', - `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', - `Nulls` bigint(11) NOT NULL DEFAULT '0', - `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', - `Std` varbinary(255) DEFAULT NULL, - `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -select * from t1 where 0=1 procedure analyse(); -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -insert into t1 values(1); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `Field_name` varbinary(255) NOT NULL DEFAULT '', - `Min_value` varbinary(255) DEFAULT NULL, - `Max_value` varbinary(255) DEFAULT NULL, - `Min_length` bigint(11) NOT NULL DEFAULT '0', - `Max_length` bigint(11) NOT NULL DEFAULT '0', - `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', - `Nulls` bigint(11) NOT NULL DEFAULT '0', - `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', - `Std` varbinary(255) DEFAULT NULL, - `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -insert into t2 select * from t1 procedure analyse(); -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -test.t1.a 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL -insert into t1 values(2); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `Field_name` varbinary(255) NOT NULL DEFAULT '', - `Min_value` varbinary(255) DEFAULT NULL, - `Max_value` varbinary(255) DEFAULT NULL, - `Min_length` bigint(11) NOT NULL DEFAULT '0', - `Max_length` bigint(11) NOT NULL DEFAULT '0', - `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', - `Nulls` bigint(11) NOT NULL DEFAULT '0', - `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', - `Std` varbinary(255) DEFAULT NULL, - `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -insert into t2 select * from t1 procedure analyse(); -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -test.t1.a 1 2 1 1 0 0 1.5000 0.5000 ENUM('1','2') NOT NULL -drop table t1,t2; create table t1 (v varchar(128)); insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),('a\0'),('b\''),('c\"'),('d\\'),('\'b'),('\"c'),('\\d'),('a\0\0\0b'),('a\'\'\'\'b'),('a\"\"\"\"b'),('a\\\\\\\\b'),('\'\0\\\"'),('\'\''),('\"\"'),('\\\\'),('The\ZEnd'); select * from t1 procedure analyse(); @@ -157,3 +86,40 @@ SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); ERROR HY000: Incorrect usage of PROCEDURE and subquery DROP TABLE t1; End of 4.1 tests +# +# Bug #48293: crash with procedure analyse, view with > 10 columns, +# having clause... +# +CREATE TABLE t1(a INT, b INT, c INT, d INT, e INT, +f INT, g INT, h INT, i INT, j INT,k INT); +INSERT INTO t1 VALUES (),(); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +#should have a derived table +EXPLAIN SELECT * FROM v1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 2 +2 DERIVED t1 ALL NULL NULL NULL NULL 2 +#should not crash +SELECT * FROM v1 PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and view +#should not crash +SELECT * FROM t1 a, v1, t1 b PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and view +#should not crash +SELECT * FROM (SELECT * FROM t1 having a > 1) x PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and subquery +#should not crash +SELECT * FROM t1 a, (SELECT * FROM t1 having a > 1) x, t1 b PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and subquery +#should not crash +SELECT 1 FROM t1 group by a having a > 1 order by 1 PROCEDURE analyse(); +ERROR HY000: Can't use ORDER clause with this procedure +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1),(2); +# should not crash +CREATE TABLE t2 SELECT 1 FROM t1, t1 t3 GROUP BY t3.a PROCEDURE ANALYSE(); +ERROR HY000: Incorrect usage of PROCEDURE and non-SELECT +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index c60ac9790c5..8fd976081d0 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -75,7 +75,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); ERROR HY000: Incorrect usage of PROCEDURE and subquery SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -ERROR HY000: Incorrect usage of PROCEDURE and subquery +ERROR HY000: Incorrect parameters to procedure 'ANALYSE' SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; ERROR 42S22: Unknown column 'a' in 'field list' SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index d8466df14bf..05f739bfd69 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -10,36 +10,13 @@ insert into t1 values (1,2,"","Y","2002-03-03"), (3,4,"","N","2002-03-04"), (5,6 select count(*) from t1 procedure analyse(); select * from t1 procedure analyse(); select * from t1 procedure analyse(2); +--error ER_WRONG_USAGE create table t2 select * from t1 procedure analyse(); -select * from t2; -drop table t1,t2; +drop table t1; --error ER_WRONG_USAGE EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); -# -# Test with impossible where -# -create table t1 (a int not null); -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -select * from t1 where 0=1 procedure analyse(); -insert into t1 values(1); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -select * from t2; -insert into t2 select * from t1 procedure analyse(); -select * from t2; -insert into t1 values(2); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -select * from t2; -insert into t2 select * from t1 procedure analyse(); -select * from t2; -drop table t1,t2; - # # Bug#2813 - analyse does not quote string values in enums from string # @@ -113,3 +90,46 @@ SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); DROP TABLE t1; --echo End of 4.1 tests + +--echo # +--echo # Bug #48293: crash with procedure analyse, view with > 10 columns, +--echo # having clause... +--echo # + +CREATE TABLE t1(a INT, b INT, c INT, d INT, e INT, + f INT, g INT, h INT, i INT, j INT,k INT); +INSERT INTO t1 VALUES (),(); + +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +--echo #should have a derived table +EXPLAIN SELECT * FROM v1; +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM v1 PROCEDURE analyse(); +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM t1 a, v1, t1 b PROCEDURE analyse(); +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM (SELECT * FROM t1 having a > 1) x PROCEDURE analyse(); +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM t1 a, (SELECT * FROM t1 having a > 1) x, t1 b PROCEDURE analyse(); +--echo #should not crash +--error ER_ORDER_WITH_PROC +SELECT 1 FROM t1 group by a having a > 1 order by 1 PROCEDURE analyse(); + +DROP VIEW v1; +DROP TABLE t1; + +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1),(2); + +--echo # should not crash +--error ER_WRONG_USAGE +CREATE TABLE t2 SELECT 1 FROM t1, t1 t3 GROUP BY t3.a PROCEDURE ANALYSE(); + +DROP TABLE t1; + + +--echo End of 5.0 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 544017ebb97..d8c08b7aa55 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -30,7 +30,7 @@ SELECT 1 IN (SELECT 1); SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); -- error ER_WRONG_USAGE select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); --- error ER_WRONG_USAGE +-- error ER_WRONG_PARAMETERS_TO_PROCEDURE SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -- error ER_BAD_FIELD_ERROR SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 79e7012346c..4b466203800 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -633,6 +633,18 @@ JOIN::prepare(Item ***rref_pointer_array, MYF(0)); /* purecov: inspected */ goto err; /* purecov: inspected */ } + if (thd->lex->derived_tables) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", + thd->lex->derived_tables & DERIVED_VIEW ? + "view" : "subquery"); + goto err; + } + if (thd->lex->sql_command != SQLCOM_SELECT) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "non-SELECT"); + goto err; + } } if (!procedure && result && result->prepare(fields_list, unit_arg)) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 12e124230e5..148ca76606f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9082,8 +9082,7 @@ procedure_clause: MYSQL_YYABORT; } - if (&lex->select_lex != lex->current_select || - lex->select_lex.get_table_list()->derived) + if (&lex->select_lex != lex->current_select) { my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); MYSQL_YYABORT; From eb969681830bb1e1f42116f556b238069448a419 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:45:33 +0100 Subject: [PATCH 07/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 1810.3964.1 > revision-id: alexey.kopytov@sun.com-20091030155453-0vlfwki805h9os62 > parent: joerg@mysql.com-20091016122941-rf6z0keqvmlgjfto > committer: Alexey Kopytov > branch nick: my50-bug48131 > timestamp: Fri 2009-10-30 18:54:53 +0300 > message: > Bug #48131: crash group by with rollup, distinct, filesort, > with temporary tables > > There were two problems the test case from this bug was > triggering: > > 1. JOIN::rollup_init() was supposed to wrap all constant Items > into another object for queries with the WITH ROLLUP modifier > to ensure they are never considered as constants and therefore > are written into temporary tables if the optimizer chooses to > employ them for DISTINCT/GROUP BY handling. > > However, JOIN::rollup_init() was called before > make_join_statistics(), so Items corresponding to fields in > const tables could not be handled as intended, which was > causing all kinds of problems later in the query execution. In > particular, create_tmp_table() assumed all constant items > except "hidden" ones to be removed earlier by remove_const() > which led to improperly initialized Field objects for the > temporary table being created. This is what was causing crashes > and valgrind errors in storage engines. > > 2. Even when the above problem had been fixed, the query from > the test case produced incorrect results due to some > DISTINCT/GROUP BY optimizations being performed by the > optimizer that are inapplicable in the WITH ROLLUP case. > > Fixed by disabling inapplicable DISTINCT/GROUP BY optimizations > when the WITH ROLLUP modifier is present, and splitting the > const-wrapping part of JOIN::rollup_init() into a separate > method which is now invoked after make_join_statistics() when > the const tables are already known. --- mysql-test/r/olap.result | 20 +++++++++ mysql-test/t/olap.test | 15 +++++++ sql/sql_select.cc | 92 ++++++++++++++++++++++++++++------------ sql/sql_select.h | 1 + 4 files changed, 100 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 4540c9d5218..a7516d97888 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -733,4 +733,24 @@ SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; 1 1 DROP TABLE t1; +# +# Bug #48131: crash group by with rollup, distinct, +# filesort, with temporary tables +# +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (100); +SELECT a, b FROM t1, t2 GROUP BY a, b WITH ROLLUP; +a b +1 100 +1 NULL +2 100 +2 NULL +NULL NULL +SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP; +b +100 +NULL +DROP TABLE t1, t2; End of 5.0 tests diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index d1e40024733..8f672af40a3 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -375,4 +375,19 @@ INSERT INTO t1 VALUES(0); SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; DROP TABLE t1; +--echo # +--echo # Bug #48131: crash group by with rollup, distinct, +--echo # filesort, with temporary tables +--echo # + +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (100); + +SELECT a, b FROM t1, t2 GROUP BY a, b WITH ROLLUP; +SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP; + +DROP TABLE t1, t2; + --echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4b466203800..94f1206f26c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -970,6 +970,12 @@ JOIN::optimize() DBUG_RETURN(1); } + if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields()) + { + DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); + DBUG_RETURN(1); + } + /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); thd_proc_info(thd, "preparing"); @@ -1100,7 +1106,7 @@ JOIN::optimize() join_tab[const_tables].select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) { - if (group_list && + if (group_list && rollup.state == ROLLUP::STATE_NONE && list_contains_unique_index(join_tab[const_tables].table, find_field_in_order_list, (void *) group_list)) @@ -1144,7 +1150,8 @@ JOIN::optimize() if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) select_distinct=0; } - else if (select_distinct && tables - const_tables == 1) + else if (select_distinct && tables - const_tables == 1 && + rollup.state == ROLLUP::STATE_NONE) { /* We are only using one table. In this case we change DISTINCT to a @@ -10203,6 +10210,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, for (; cur_group ; cur_group= cur_group->next, key_part_info++) { Field *field=(*cur_group->item)->get_tmp_table_field(); + DBUG_ASSERT(field->table == table); bool maybe_null=(*cur_group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; @@ -15622,32 +15630,7 @@ bool JOIN::rollup_init() { item->maybe_null= 1; found_in_group= 1; - if (item->const_item()) - { - /* - For ROLLUP queries each constant item referenced in GROUP BY list - is wrapped up into an Item_func object yielding the same value - as the constant item. The objects of the wrapper class are never - considered as constant items and besides they inherit all - properties of the Item_result_field class. - This wrapping allows us to ensure writing constant items - into temporary tables whenever the result of the ROLLUP - operation has to be written into a temporary table, e.g. when - ROLLUP is used together with DISTINCT in the SELECT list. - Usually when creating temporary tables for a intermidiate - result we do not include fields for constant expressions. - */ - Item* new_item= new Item_func_rollup_const(item); - if (!new_item) - return 1; - new_item->fix_fields(thd, (Item **) 0); - thd->change_item_tree(it.ref(), new_item); - for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) - { - if (*tmp->item == item) - thd->change_item_tree(tmp->item, new_item); - } - } + break; } } if (item->type() == Item::FUNC_ITEM && !found_in_group) @@ -15666,6 +15649,59 @@ bool JOIN::rollup_init() } return 0; } + +/** + Wrap all constant Items in GROUP BY list. + + For ROLLUP queries each constant item referenced in GROUP BY list + is wrapped up into an Item_func object yielding the same value + as the constant item. The objects of the wrapper class are never + considered as constant items and besides they inherit all + properties of the Item_result_field class. + This wrapping allows us to ensure writing constant items + into temporary tables whenever the result of the ROLLUP + operation has to be written into a temporary table, e.g. when + ROLLUP is used together with DISTINCT in the SELECT list. + Usually when creating temporary tables for a intermidiate + result we do not include fields for constant expressions. + + @retval + 0 if ok + @retval + 1 on error +*/ + +bool JOIN::rollup_process_const_fields() +{ + ORDER *group_tmp; + Item *item; + List_iterator it(all_fields); + + for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) + { + if (!(*group_tmp->item)->const_item()) + continue; + while ((item= it++)) + { + if (*group_tmp->item == item) + { + Item* new_item= new Item_func_rollup_const(item); + if (!new_item) + return 1; + new_item->fix_fields(thd, (Item **) 0); + thd->change_item_tree(it.ref(), new_item); + for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) + { + if (*tmp->item == item) + thd->change_item_tree(tmp->item, new_item); + } + break; + } + } + it.rewind(); + } + return 0; +} /** diff --git a/sql/sql_select.h b/sql/sql_select.h index a0366d47149..4c729fa915c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -502,6 +502,7 @@ public: } bool rollup_init(); + bool rollup_process_const_fields(); bool rollup_make_fields(List &all_fields, List &fields, Item_sum ***func); int rollup_send_data(uint idx); From d8f41c85933d5c1ebee239ba1c5e2958f626e89f Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:52:26 +0100 Subject: [PATCH 08/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 1810.3961.7 > committer: Georgi Kodinov > branch nick: B48291-5.0-bugteam > timestamp: Fri 2009-10-30 15:15:43 +0200 > message: > Bug #48291 : crash with row() operator,select into @var, and > subquery returning multiple rows > > Error handling was missing when handling subqueires in WHERE > and when assigning a SELECT result to a @variable. > This caused crash(es). > > Fixed by adding error handling code to both the WHERE > condition evaluation and to assignment to an @variable. > ------------------------------------------------------------ --- mysql-test/r/select.result | 12 ++++++++++++ mysql-test/t/select.test | 17 +++++++++++++++++ sql/sql_class.cc | 6 ++++-- sql/sql_select.cc | 13 ++++++++++++- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index a41f95de077..1b615233a14 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4415,6 +4415,18 @@ SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); 1 1 DROP TABLE t1; +# +# Bug #48291 : crash with row() operator,select into @var, and +# subquery returning multiple rows +# +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (2),(3); +# Should not crash +SELECT 1 FROM t1 WHERE a <> 1 AND NOT +ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1)) +INTO @var0; +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1; End of 5.0 tests create table t1(a INT, KEY (a)); INSERT INTO t1 VALUES (1),(2),(3),(4),(5); diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 1e7e853da32..51f0cd73374 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3755,7 +3755,24 @@ EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); DROP TABLE t1; + +--echo # +--echo # Bug #48291 : crash with row() operator,select into @var, and +--echo # subquery returning multiple rows +--echo # + +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (2),(3); + +--echo # Should not crash +--error ER_SUBQUERY_NO_1_ROW +SELECT 1 FROM t1 WHERE a <> 1 AND NOT +ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1)) +INTO @var0; + +DROP TABLE t1; + --echo End of 5.0 tests # diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f75dc2cb88a..6f8b5bd6be9 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2715,9 +2715,11 @@ bool select_dumpvar::send_data(List &items) else { Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item); - suv->fix_fields(thd, 0); + if (suv->fix_fields(thd, 0)) + DBUG_RETURN (1); suv->save_item_result(item); - suv->update(); + if (suv->update()) + DBUG_RETURN (1); } } DBUG_RETURN(thd->is_error()); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 94f1206f26c..55ea1c81782 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11182,6 +11182,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, bool not_used_in_distinct=join_tab->not_used_in_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; + bool select_cond_result= TRUE; if (error > 0 || (join->thd->is_error())) // Fatal error return NESTED_LOOP_ERROR; @@ -11193,7 +11194,17 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_KILLED; /* purecov: inspected */ } DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); - if (!select_cond || select_cond->val_int()) + + if (select_cond) + { + select_cond_result= test(select_cond->val_int()); + + /* check for errors evaluating the condition */ + if (join->thd->is_error()) + return NESTED_LOOP_ERROR; + } + + if (!select_cond || select_cond_result) { /* There is no select condition or the attached pushed down From cb115003f4fd271b9924adeaebb3b9fb367d268d Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:56:33 +0100 Subject: [PATCH 09/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3148.13.3 > revision-id: svoj@sun.com-20091102144140-8de1z6mdy5dopw3j > parent: svoj@sun.com-20091102143655-lo69f57p82nky58q > committer: Sergey Vojtovich > branch nick: mysql-5.1-bugteam > timestamp: Mon 2009-11-02 18:41:40 +0400 > message: > Applying InnoDB snashot 5.1-ss6129 > > Detailed revision comments: > > r6045 | jyang | 2009-10-08 02:27:08 +0300 (Thu, 08 Oct 2009) | 7 lines > branches/5.1: Fix bug #47777. Treat the Geometry data same as > Binary BLOB in ha_innobase::store_key_val_for_row(), since the > Geometry data is stored as Binary BLOB in Innodb. > > Review: rb://180 approved by Marko Makela. --- storage/innobase/handler/ha_innodb.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a8b9b678282..698e9ac8e28 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3240,7 +3240,10 @@ ha_innobase::store_key_val_for_row( } else if (mysql_type == MYSQL_TYPE_TINY_BLOB || mysql_type == MYSQL_TYPE_MEDIUM_BLOB || mysql_type == MYSQL_TYPE_BLOB - || mysql_type == MYSQL_TYPE_LONG_BLOB) { + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { CHARSET_INFO* cs; ulint key_len; From 6d027f4ba69b69598dc0186e14a7a9bc5a80494e Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 17:58:51 +0100 Subject: [PATCH 10/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3148.13.4 > revision-id: svoj@sun.com-20091102144320-0hz2ti21em510ee5 > parent: svoj@sun.com-20091102144140-8de1z6mdy5dopw3j > committer: Sergey Vojtovich > branch nick: mysql-5.1-bugteam > timestamp: Mon 2009-11-02 18:43:20 +0400 > message: > Applying InnoDB snashot 5.1-ss6129 > > Detailed revision comments: > > r6051 | sunny | 2009-10-12 07:05:00 +0300 (Mon, 12 Oct 2009) | 6 lines > branches/5.1: Ignore negative values supplied by the user when calculating the > next value to store in dict_table_t. Setting autoincrement columns top negative > values is undefined behavior and this change should bring the behavior of > InnoDB closer to what users expect. Added several tests to check. > rb://162 --- mysql-test/r/innodb-autoinc.result | 215 ++++++++++++++++++++++++++ mysql-test/t/innodb-autoinc.test | 105 +++++++++++++ storage/innobase/handler/ha_innodb.cc | 4 +- 3 files changed, 323 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index d2e8eb19e0c..ce96baf11c1 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -889,3 +889,218 @@ d1 3 4 DROP TABLE t1; +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +SHOW VARIABLES LIKE "%auto_inc%"; +Variable_name Value +auto_increment_increment 1 +auto_increment_offset 1 +CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-127, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` tinyint(4) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-127 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-127, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` tinyint(3) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-32767, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` smallint(6) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-32767 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-32757, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-8388607, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` mediumint(9) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-8388607 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-8388607, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-2147483647 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(10) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(20) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-9223372036854775807 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index 61c42f45733..a4ffc64c99f 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -498,3 +498,108 @@ ALTER TABLE t1 AUTO_INCREMENT = 3; INSERT INTO t1 VALUES(null); SELECT * FROM t1; DROP TABLE t1; + +# If the user has specified negative values for an AUTOINC column then +# InnoDB should ignore those values when setting the table's max value. +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +SHOW VARIABLES LIKE "%auto_inc%"; +# TINYINT +CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-127, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-127, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# SMALLINT +# +CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-32767, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-32757, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# MEDIUMINT +# +CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-8388607, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-8388607, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# INT +# +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# BIGINT +# +CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +# End negative number check diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 698e9ac8e28..41b5c9f8311 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7868,6 +7868,7 @@ ha_innobase::get_auto_increment( AUTOINC counter after attempting to insert the row. */ if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) { ulonglong need; + ulonglong current; ulonglong next_value; ulonglong col_max_value; @@ -7876,11 +7877,12 @@ ha_innobase::get_auto_increment( col_max_value = innobase_get_int_col_max_value( table->next_number_field); + current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; /* Compute the last value in the interval */ next_value = innobase_next_autoinc( - *first_value, need, offset, col_max_value); + current, need, offset, col_max_value); prebuilt->autoinc_last_value = next_value; From c084d7010b62706979198903c32de1132f4837c4 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:00:46 +0100 Subject: [PATCH 11/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3148.8.5 > revision-id: davi.arnaut@sun.com-20091102112139-pztthzy6qj8jzomn > parent: svoj@sun.com-20091103091902-vwszwwpfi1f4zrpn > committer: Davi Arnaut > branch nick: 48370-5.1 > timestamp: Mon 2009-11-02 09:21:39 -0200 > message: > Bug#48370: Absolutely wrong calculations with GROUP BY and decimal fields when using IF > Bug#45261: Crash, stored procedure + decimal > > Revert fix for Bug#45261 due to unforeseen bugs. --- mysql-test/r/type_newdecimal.result | 220 +--------------------------- mysql-test/t/type_newdecimal.test | 134 ----------------- sql/field.cc | 85 ----------- sql/field.h | 9 -- sql/item.cc | 25 ++-- sql/item.h | 3 +- sql/item_cmpfunc.cc | 6 +- sql/item_func.cc | 52 +++++-- sql/item_func.h | 1 - sql/item_sum.cc | 3 +- sql/my_decimal.h | 14 +- sql/sql_select.cc | 41 +++++- 12 files changed, 110 insertions(+), 483 deletions(-) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index c3d1e400b23..748aadee4fb 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -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); SELECT a+CAST(1 AS decimal(65,30)) AS aa, SUM(b) FROM t1 GROUP BY aa; aa SUM(b) -2.00000000000000000000000000000 10 -3.00000000000000000000000000000 10 -4.00000000000000000000000000000 30 +2.000000000000000000000000000000 10 +3.000000000000000000000000000000 10 +4.000000000000000000000000000000 30 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. DROP TABLE t1; @@ -1521,13 +1521,13 @@ f1 DROP TABLE t1; CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1; 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; Field Type Null Key Default Extra -f1 decimal(65,20) NO 0.00000000000000000000 +f1 decimal(65,30) NO 0.000000000000000000000000000000 SELECT f1 FROM t1; f1 -123451234512345123451234512345123451234512345.67890678906789067891 +99999999999999999999999999999999999.999999999999999999999999999999 DROP TABLE t1; select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 * 1.01500000 * 1.01500000 * 0.99500000); @@ -1595,7 +1595,7 @@ Warnings: Note 1265 Data truncated for column 'my_col' at row 1 DESCRIBE t1; 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; my_col 1.123456789123456789123456789123 @@ -1625,212 +1625,8 @@ Warnings: Note 1265 Data truncated for column 'my_col' at row 1 DESCRIBE t1; 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; my_col 0.012345687012345687012345687012 DROP TABLE t1; -# -# Bug#45261: Crash, stored procedure + decimal -# -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 SELECT -/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 -AS c1; -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. -AS c1; -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ -AS c1; -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 -AS c1; -Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ -AS c1; -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; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 65bafaae77e..cd3c3f81510 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1286,137 +1286,3 @@ CREATE TABLE t1 SELECT 1 % .1234567891234567891234567891234567891234567891234567 DESCRIBE t1; SELECT my_col FROM t1; DROP TABLE t1; - ---echo # ---echo # Bug#45261: Crash, stored procedure + decimal ---echo # - ---disable_warnings -DROP TABLE IF EXISTS t1; ---enable_warnings - -CREATE TABLE t1 SELECT - /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - .100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - .123456789012345678901234567890123456789012345678901234567890123456 /* 66 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - ---echo # ---echo # Test that the integer and decimal parts are properly calculated. ---echo # - -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; -DESC t2; -DROP TABLE t1,t2; - -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1; -DESC t2; -DROP TABLE t1,t2; - -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1; -DESC t2; -DROP TABLE t1,t2; - ---echo # ---echo # Test that variables get maximum precision. ---echo # - -SET @decimal= 1.1; -CREATE TABLE t1 SELECT @decimal AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 0df9b0fc2e4..0ec5b3a9aed 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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); set_if_smaller(precision, DECIMAL_MAX_PRECISION); - DBUG_ASSERT(precision >= dec); DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) && (dec <= DECIMAL_MAX_SCALE)); 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) { store_value(&decimal_zero); diff --git a/sql/field.h b/sql/field.h index 7a9b69eff40..a58a95a1f77 100644 --- a/sql/field.h +++ b/sql/field.h @@ -615,10 +615,6 @@ protected: class Field_num :public Field { public: - /** - The scale of the Field's value, i.e. the number of digits to the right - of the decimal point. - */ const uint8 dec; bool zerofill,unsigned_flag; // Purify cannot handle bit fields Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, @@ -777,11 +773,6 @@ public: Field_new_decimal(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, uint8 dec_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 ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } Item_result result_type () const { return DECIMAL_RESULT; } diff --git a/sql/item.cc b/sql/item.cc index 86e4551e55b..613310e483e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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 precision= max_length; Item_result restype= result_type(); if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) - precision= my_decimal_length_to_precision(max_length, decimals, unsigned_flag); - - return precision; + { + uint prec= + 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()) { case MYSQL_TYPE_DECIMAL: 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; case MYSQL_TYPE_TINY: field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, diff --git a/sql/item.h b/sql/item.h index a2cff3ab3a9..73f1fc6feed 100644 --- a/sql/item.h +++ b/sql/item.h @@ -762,10 +762,9 @@ public: virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const { 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; 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 will not change until next fix_fields) and its value is known. diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c29031d25b5..ab59da42ae0 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2191,7 +2191,7 @@ uint Item_func_ifnull::decimal_precision() const int arg1_int_part= args[1]->decimal_int_part(); int max_int_part= max(arg0_int_part, arg1_int_part); int precision= max_int_part + decimals; - return precision; + return min(precision, DECIMAL_MAX_PRECISION); } @@ -2375,7 +2375,7 @@ uint Item_func_if::decimal_precision() const int arg1_prec= args[1]->decimal_int_part(); int arg2_prec= args[2]->decimal_int_part(); int precision=max(arg1_prec,arg2_prec) + decimals; - return precision; + return min(precision, DECIMAL_MAX_PRECISION); } @@ -2783,7 +2783,7 @@ uint Item_func_case::decimal_precision() const if (else_expr_num != -1) 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); } diff --git a/sql/item_func.cc b/sql/item_func.cc index d9e6f76dd6b..ac52f36474a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -451,8 +451,45 @@ Field *Item_func::tmp_table_field(TABLE *table) return make_string_field(table); break; 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; + } case ROW_RESULT: default: // 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 { return (!var_entry || current_thd->query_id != var_entry->update_query_id); diff --git a/sql/item_func.h b/sql/item_func.h index fdbbff89e60..025ac12fe07 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1393,7 +1393,6 @@ public: table_map used_tables() const { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; - uint decimal_precision() const; private: bool set_value(THD *thd, sp_rcontext *ctx, Item **it); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 08a48c6ce2f..38251294053 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -517,7 +517,8 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, name, table->s, collation.collation); break; 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; case ROW_RESULT: default: diff --git a/sql/my_decimal.h b/sql/my_decimal.h index b1df1395dcd..21669e82c44 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -48,12 +48,10 @@ C_MODE_END 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 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_SCALE 30 +#define DECIMAL_NOT_SPECIFIED 31 /** 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. @@ -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, - uint scale, + uint8 scale, bool unsigned_flag) { /* @@ -192,7 +196,7 @@ inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, (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) { /* diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 55ea1c81782..34d23ace89b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9409,8 +9409,47 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; 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; + } case ROW_RESULT: default: // This case should never be choosen From 3b0456570422c0ddadec247c3aac60b738b013bb Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:04:39 +0100 Subject: [PATCH 12/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3148.9.3 > revision-id: azundris@mysql.com-20091029230154-jp2xqvzw2nhj9q41 > parent: azundris@mysql.com-20091027095316-54lwjr9vqkscq1ik > committer: Tatiana A. Nurnberg > branch nick: 51-48295 > timestamp: Thu 2009-10-29 16:01:54 -0700 > message: > Bug#48295: explain extended crash with subquery and ONLY_FULL_GROUP_BY sql_mode > > If an outer query is broken, a subquery might not even get set up. > EXPLAIN EXTENDED did not expect this and merrily tried to de-ref all > of the half-setup info. > > We now catch this case and print as much as we have, as it doesn't cost us > anything (doesn't make regular execution slower). --- mysql-test/r/explain.result | 16 ++++++++++++++++ mysql-test/t/explain.test | 20 ++++++++++++++++++++ sql/item_subselect.cc | 11 ++++++++--- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 96fcbc33d3f..5a1bf1a1290 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -194,4 +194,20 @@ dt 2001-01-01 01:01:01 2001-01-01 01:01:01 drop tables t1, t2; +# +# Bug#48295: +# explain extended crash with subquery and ONLY_FULL_GROUP_BY sql_mode +# +CREATE TABLE t1 (f1 INT); +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; +EXPLAIN EXTENDED SELECT 1 FROM t1 +WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); +ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause +SHOW WARNINGS; +Level Code Message +Error 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause +Note 1003 select 1 AS `1` from `test`.`t1` where ((...)) +SET SESSION sql_mode=@old_sql_mode; +DROP TABLE t1; End of 5.1 tests. diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 18f1145a25d..77b49a8b1a5 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -167,4 +167,24 @@ flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); drop tables t1, t2; +--echo # +--echo # Bug#48295: +--echo # explain extended crash with subquery and ONLY_FULL_GROUP_BY sql_mode +--echo # + +CREATE TABLE t1 (f1 INT); + +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; + +# EXPLAIN EXTENDED (with subselect). used to crash. should give NOTICE. +--error ER_MIX_OF_GROUP_FUNC_AND_FIELDS +EXPLAIN EXTENDED SELECT 1 FROM t1 + WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); +SHOW WARNINGS; + +SET SESSION sql_mode=@old_sql_mode; + +DROP TABLE t1; + --echo End of 5.1 tests. diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index da651cec70c..29db9eb0903 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -311,9 +311,14 @@ void Item_subselect::update_used_tables() void Item_subselect::print(String *str, enum_query_type query_type) { - str->append('('); - engine->print(str, query_type); - str->append(')'); + if (engine) + { + str->append('('); + engine->print(str, query_type); + str->append(')'); + } + else + str->append("(...)"); } From b84555efaeb51c1215e154ef251c76e295e61b9d Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:09:30 +0100 Subject: [PATCH 13/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3148.9.6 > revision-id: martin.hansson@sun.com-20091102122407-krzh4h0i052lbwr5 > parent: davi.arnaut@sun.com-20091102112236-k3myix2xy8miyv4s > committer: Martin Hansson > branch nick: 5.1bt > timestamp: Mon 2009-11-02 13:24:07 +0100 > message: > Bug#47925: regression of range optimizer and date comparison in 5.1.39! > > When a query was using a DATE or DATETIME value formatted > using any other separator characters beside hyphen '-', a > query with a greater-or-equal '>=' condition matching only > the greatest value in an indexed column, the result was > empty if index range scan was employed. > > The range optimizer got a new feature between 5.1.38 and > 5.1.39 that changes a greater-or-equal condition to a > greater-than if the value matching that in the query was not > present in the table. But the value comparison function > compared the dates as strings instead of dates. > > The bug was fixed by splitting the function > get_date_from_str in two: One part that parses and does > error checking. This function is now visible outside the > module. The old get_date_from_str now calls the new > function. --- mysql-test/r/range.result | 198 ++++++++++++++++++++++++++++++++++++++ mysql-test/t/range.test | 80 +++++++++++++++ sql/item.cc | 61 +++++++----- sql/item.h | 2 +- sql/item_cmpfunc.cc | 102 ++++++++++++-------- sql/item_cmpfunc.h | 3 + sql/opt_range.cc | 6 +- sql/time.cc | 16 +-- 8 files changed, 393 insertions(+), 75 deletions(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index cc5e8d2be96..c5842bc45aa 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1219,3 +1219,201 @@ explain select * from t2 where a=1000 and b<11; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref a a 5 const 502 Using where drop table t1, t2; +# +# Bug#47925: regression of range optimizer and date comparison in 5.1.39! +# +CREATE TABLE t1 ( a DATE, KEY ( a ) ); +CREATE TABLE t2 ( a DATETIME, KEY ( a ) ); +# Make optimizer choose range scan +INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22'); +INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23'); +INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'), +('2009-09-22 12:00:00'); +INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'), +('2009-09-23 12:00:00'); +# DATE vs DATE +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t1 WHERE a >= '2009/09/23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '20090923'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= 20090923; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009-9-23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009.09.23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009:09:23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +# DATE vs DATETIME +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t2 WHERE a >= '2009/09/23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009/09/23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '20090923'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= 20090923; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009-9-23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009.09.23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009:09:23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +# DATETIME vs DATETIME +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '20090923120000'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= 20090923120000; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009-9-23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009.09.23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009:09:23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +# DATETIME vs DATE +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '20090923000000'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= 20090923000000; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009-9-23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009.09.23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009:09:23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +# Test of the new get_date_from_str implementation +# Behavior differs slightly between the trunk and mysql-pe. +# The former may give errors for the truncated values, while the latter +# gives warnings. The purpose of this test is not to interfere, and only +# preserve existing behavior. +SELECT str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND +str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20'; +str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND +str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20' +1 +Warnings: +Warning 1292 Truncated incorrect date value: '' +SELECT str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND +str_to_date('2007-20-00', '%Y-%m-%d') <= ''; +str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND +str_to_date('2007-20-00', '%Y-%m-%d') <= '' +NULL +Warnings: +Warning 1292 Truncated incorrect date value: '' +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; +str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20' +1 +Warnings: +Warning 1292 Truncated incorrect datetime value: '' +SELECT str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND ''; +str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND '' +NULL +Warnings: +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +SELECT str_to_date('', '%Y-%m-%d'); +str_to_date('', '%Y-%m-%d') +0000-00-00 +DROP TABLE t1, t2; +End of 5.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index e1411e7fd46..ddddb66f38d 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1046,3 +1046,83 @@ explain select * from t2 where a=1000 and b<11; drop table t1, t2; +--echo # +--echo # Bug#47925: regression of range optimizer and date comparison in 5.1.39! +--echo # +CREATE TABLE t1 ( a DATE, KEY ( a ) ); +CREATE TABLE t2 ( a DATETIME, KEY ( a ) ); + +--echo # Make optimizer choose range scan +INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22'); +INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23'); + +INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'), + ('2009-09-22 12:00:00'); +INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'), + ('2009-09-23 12:00:00'); + +--echo # DATE vs DATE +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23'; +SELECT * FROM t1 WHERE a >= '2009/09/23'; +SELECT * FROM t1 WHERE a >= '20090923'; +SELECT * FROM t1 WHERE a >= 20090923; +SELECT * FROM t1 WHERE a >= '2009-9-23'; +SELECT * FROM t1 WHERE a >= '2009.09.23'; +SELECT * FROM t1 WHERE a >= '2009:09:23'; + +--echo # DATE vs DATETIME +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '20090923'; +SELECT * FROM t2 WHERE a >= 20090923; +SELECT * FROM t2 WHERE a >= '2009-9-23'; +SELECT * FROM t2 WHERE a >= '2009.09.23'; +SELECT * FROM t2 WHERE a >= '2009:09:23'; + +--echo # DATETIME vs DATETIME +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +SELECT * FROM t2 WHERE a >= '20090923120000'; +SELECT * FROM t2 WHERE a >= 20090923120000; +SELECT * FROM t2 WHERE a >= '2009-9-23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009.09.23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009:09:23 12:00:00'; + +--echo # DATETIME vs DATE +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '20090923000000'; +SELECT * FROM t1 WHERE a >= 20090923000000; +SELECT * FROM t1 WHERE a >= '2009-9-23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009.09.23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009:09:23 00:00:00'; + +--echo # Test of the new get_date_from_str implementation +--echo # Behavior differs slightly between the trunk and mysql-pe. +--echo # The former may give errors for the truncated values, while the latter +--echo # gives warnings. The purpose of this test is not to interfere, and only +--echo # preserve existing behavior. +SELECT str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND + str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20'; + +SELECT str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND + str_to_date('2007-20-00', '%Y-%m-%d') <= ''; + +SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; +SELECT str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND ''; + +SELECT str_to_date('', '%Y-%m-%d'); + +DROP TABLE t1, t2; + +--echo End of 5.1 tests diff --git a/sql/item.cc b/sql/item.cc index 613310e483e..8f487872f1b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6859,52 +6859,61 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) } /** - Compare the value stored in field, with the original item. + Compare the value stored in field with the expression from the query. - @param field field which the item is converted and stored in - @param item original item + @param field Field which the Item is stored in after conversion + @param item Original expression from query - @return Return an integer greater than, equal to, or less than 0 if - the value stored in the field is greater than, equal to, - or less than the original item + @return Returns an integer greater than, equal to, or less than 0 if + the value stored in the field is greater than, equal to, + or less than the original Item. A 0 may also be returned if + out of memory. @note We only use this on the range optimizer/partition pruning, because in some cases we can't store the value in the field without some precision/character loss. */ -int stored_field_cmp_to_item(Field *field, Item *item) +int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) { - Item_result res_type=item_cmp_type(field->result_type(), item->result_type()); if (res_type == STRING_RESULT) { char item_buff[MAX_FIELD_WIDTH]; char field_buff[MAX_FIELD_WIDTH]; - String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result; + + String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin); String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); - enum_field_types field_type; - item_result=item->val_str(&item_tmp); + String *item_result= item->val_str(&item_tmp); + /* + Some implementations of Item::val_str(String*) actually modify + the field Item::null_value, hence we can't check it earlier. + */ if (item->null_value) return 0; - field->val_str(&field_tmp); + String *field_result= field->val_str(&field_tmp); - /* - If comparing DATE with DATETIME, append the time-part to the DATE. - So that the strings are equally formatted. - A DATE converted to string is 10 characters, and a DATETIME converted - to string is 19 characters. - */ - field_type= field->type(); - if (field_type == MYSQL_TYPE_DATE && - item_result->length() == 19) - field_tmp.append(" 00:00:00"); - else if (field_type == MYSQL_TYPE_DATETIME && - item_result->length() == 10) - item_result->append(" 00:00:00"); + enum_field_types field_type= field->type(); - return stringcmp(&field_tmp,item_result); + if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME) + { + enum_mysql_timestamp_type type= MYSQL_TIMESTAMP_ERROR; + + if (field_type == MYSQL_TYPE_DATE) + type= MYSQL_TIMESTAMP_DATE; + + if (field_type == MYSQL_TYPE_DATETIME) + type= MYSQL_TIMESTAMP_DATETIME; + + const char *field_name= field->field_name; + MYSQL_TIME field_time, item_time; + get_mysql_time_from_str(thd, field_result, type, field_name, &field_time); + get_mysql_time_from_str(thd, item_result, type, field_name, &item_time); + + return my_time_compare(&field_time, &item_time); + } + return stringcmp(field_result, item_result); } if (res_type == INT_RESULT) return 0; // Both are of type int diff --git a/sql/item.h b/sql/item.h index 73f1fc6feed..3a4b6e53b3a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3124,4 +3124,4 @@ void mark_select_range_as_dependent(THD *thd, extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); -extern int stored_field_cmp_to_item(Field *field, Item *item); +extern int stored_field_cmp_to_item(THD *thd, Field *field, Item *item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index ab59da42ae0..df92c165f2d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -636,6 +636,62 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) return 0; } +/** + Parse date provided in a string to a MYSQL_TIME. + + @param[in] thd Thread handle + @param[in] str A string to convert + @param[in] warn_type Type of the timestamp for issuing the warning + @param[in] warn_name Field name for issuing the warning + @param[out] l_time The MYSQL_TIME objects is initialized. + + Parses a date provided in the string str into a MYSQL_TIME object. If the + string contains an incorrect date or doesn't correspond to a date at all + then a warning is issued. The warn_type and the warn_name arguments are used + as the name and the type of the field when issuing the warning. If any input + was discarded (trailing or non-timestamp-y characters), return value will be + TRUE. + + @return Status flag + @retval FALSE Success. + @retval True Indicates failure. +*/ + +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time) +{ + bool value; + int error; + enum_mysql_timestamp_type timestamp_type; + + timestamp_type= + str_to_datetime(str->ptr(), str->length(), l_time, + (TIME_FUZZY_DATE | MODE_INVALID_DATES | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), + &error); + + if (timestamp_type == MYSQL_TIMESTAMP_DATETIME || + timestamp_type == MYSQL_TIMESTAMP_DATE) + /* + Do not return yet, we may still want to throw a "trailing garbage" + warning. + */ + value= FALSE; + else + { + value= TRUE; + error= 1; /* force warning */ + } + + if (error > 0) + make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + str->ptr(), str->length(), + warn_type, warn_name); + + return value; +} + /** @brief Convert date provided in a string to the int representation. @@ -650,51 +706,21 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) representation. If the string contains wrong date or doesn't contain it at all then a warning is issued. The warn_type and the warn_name arguments are used as the name and the type of the - field when issuing the warning. If any input was discarded - (trailing or non-timestampy characters), was_cut will be non-zero. - was_type will return the type str_to_datetime() could correctly - extract. + field when issuing the warning. @return converted value. 0 on error and on zero-dates -- check 'failure' */ - -static ulonglong -get_date_from_str(THD *thd, String *str, timestamp_type warn_type, - char *warn_name, bool *error_arg) +static ulonglong get_date_from_str(THD *thd, String *str, + timestamp_type warn_type, + const char *warn_name, bool *error_arg) { - ulonglong value= 0; - int error; MYSQL_TIME l_time; - enum_mysql_timestamp_type ret; + *error_arg= get_mysql_time_from_str(thd, str, warn_type, warn_name, &l_time); - ret= str_to_datetime(str->ptr(), str->length(), &l_time, - (TIME_FUZZY_DATE | MODE_INVALID_DATES | - (thd->variables.sql_mode & - (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), - &error); - - if (ret == MYSQL_TIMESTAMP_DATETIME || ret == MYSQL_TIMESTAMP_DATE) - { - /* - Do not return yet, we may still want to throw a "trailing garbage" - warning. - */ - *error_arg= FALSE; - value= TIME_to_ulonglong_datetime(&l_time); - } - else - { - *error_arg= TRUE; - error= 1; /* force warning */ - } - - if (error > 0) - make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - str->ptr(), str->length(), - warn_type, warn_name); - - return value; + if (*error_arg) + return 0; + return TIME_to_ulonglong_datetime(&l_time); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c2227fa04e0..437d9541e50 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1721,3 +1721,6 @@ inline Item *and_conds(Item *a, Item *b) } Item *and_expressions(Item *a, Item *b, Item **org_item); + +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 68c70c915c3..4112f40b683 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5954,7 +5954,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, switch (type) { case Item_func::LT_FUNC: - if (stored_field_cmp_to_item(field,value) == 0) + if (stored_field_cmp_to_item(param->thd, field, value) == 0) tree->max_flag=NEAR_MAX; /* fall through */ case Item_func::LE_FUNC: @@ -5969,14 +5969,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, case Item_func::GT_FUNC: /* Don't use open ranges for partial key_segments */ if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(field, value) <= 0)) + (stored_field_cmp_to_item(param->thd, field, value) <= 0)) tree->min_flag=NEAR_MIN; tree->max_flag= NO_MAX_RANGE; break; case Item_func::GE_FUNC: /* Don't use open ranges for partial key_segments */ if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(field,value) < 0)) + (stored_field_cmp_to_item(param->thd, field, value) < 0)) tree->min_flag= NEAR_MIN; tree->max_flag=NO_MAX_RANGE; break; diff --git a/sql/time.cc b/sql/time.cc index 962b65e454c..8b554beb94b 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -965,20 +965,22 @@ calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *s 0 - a == b 1 - a > b - NOTES - TIME.second_part is not considered during comparison */ -int -my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) +int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) { - my_ulonglong a_t= TIME_to_ulonglong_datetime(a); - my_ulonglong b_t= TIME_to_ulonglong_datetime(b); + ulonglong a_t= TIME_to_ulonglong_datetime(a); + ulonglong b_t= TIME_to_ulonglong_datetime(b); + if (a_t < b_t) + return -1; if (a_t > b_t) return 1; - else if (a_t < b_t) + + if (a->second_part < b->second_part) return -1; + if (a->second_part > b->second_part) + return 1; return 0; } From 233dc05f392b5c541b6877013c113ae1333589ea Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:11:54 +0100 Subject: [PATCH 14/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3181 > revision-id: alexey.kopytov@sun.com-20091016201951-fsht0wm8xn8vkzsx > parent: joerg@mysql.com-20091016164025-kb4sbrggq5o7zufc > committer: Alexey Kopytov > branch nick: mysql-5.1-bugteam > timestamp: Sat 2009-10-17 00:19:51 +0400 > message: > Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN > > The problem was in incorrect handling of predicates involving > NULL as a constant value by the range optimizer. > > For example, when creating a SEL_ARG node from a condition of > the form "field < const" (which would normally result in the > "NULL < field < const" SEL_ARG), the special case when "const" > is NULL was not taken into account, so "NULL < field < NULL" > was produced for the "field < NULL" condition. > > As a result, SEL_ARG structures of this form could not be > further optimized which in turn could lead to incorrectly > constructed SEL_ARG trees. In particular, code assuming SEL_ARG > structures to always form a sequence of ordered disjoint > intervals could enter an infinite loop under some > circumstances. > > Fixed by changing get_mm_leaf() so that for any sargable > predicate except "<=>" involving NULL as a constant, "empty" > SEL_ARG is returned, since such a predicate is always false. --- mysql-test/r/partition_pruning.result | 3 +-- mysql-test/r/range.result | 8 ++++++++ mysql-test/r/subselect.result | 3 +-- mysql-test/t/range.test | 9 +++++++++ sql/opt_range.cc | 11 +++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 769d499fc0a..3128c57b2cf 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -1272,10 +1272,9 @@ 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 t1 p20090401 ALL NULL NULL NULL NULL 2 Using where +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 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/range.result b/mysql-test/r/range.result index c5842bc45aa..3ed2c3f53d0 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1216,6 +1216,14 @@ select 'In following EXPLAIN the access method should be ref, #rows~=500 (and no Z In following EXPLAIN the access method should be ref, #rows~=500 (and not 2) explain select * from t2 where a=1000 and b<11; +# +# Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN +# +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (1), (NULL); +SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); +a +DROP TABLE t1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref a a 5 const 502 Using where drop table t1, t2; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 8fd976081d0..3a736849f94 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4403,8 +4403,7 @@ FROM t1 WHERE a = 230; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables -2 DEPENDENT SUBQUERY st1 index NULL a 5 NULL 2 Using index -2 DEPENDENT SUBQUERY st2 index b b 5 NULL 2 Using where; Using index; Using join buffer +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) FROM t1 WHERE a = 230; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index ddddb66f38d..272df5f272e 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1043,6 +1043,15 @@ alter table t2 add index (a,b); select 'In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)' Z; explain select * from t2 where a=1000 and b<11; +--echo # +--echo # Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN +--echo # + +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (1), (NULL); +SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); +DROP TABLE t1; + drop table t1, t2; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 4112f40b683..b4d778089a9 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5911,6 +5911,17 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, goto end; } field->table->in_use->variables.sql_mode= orig_sql_mode; + + /* + Any sargable predicate except "<=>" involving NULL as a constant is always + FALSE + */ + if (type != Item_func::EQUAL_FUNC && field->is_real_null()) + { + tree= &null_element; + goto end; + } + str= (uchar*) alloc_root(alloc, key_part->store_length+1); if (!str) goto end; From cf3dc5b07ceeb0e6a84cb2babbd29d0da7602f0f Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:14:34 +0100 Subject: [PATCH 15/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3182 [merge] > revision-id: ramil@mysql.com-20091018162655-z4dlolfx5s0zem8l > parent: alexey.kopytov@sun.com-20091016201951-fsht0wm8xn8vkzsx > parent: ramil@mysql.com-20091013044327-24km05wc060ied87 > committer: Ramil Kalimullin > branch nick: mysql-5.1-bugteam > timestamp: Sun 2009-10-18 21:26:55 +0500 > message: > Fix for bug#47963: Wrong results when index is used > > Problem: using null microsecond part in a WHERE condition > (e.g. WHERE date_time_field <= "YYYY-MM-DD HH:MM:SS.0000") > may lead to wrong results due to improper DATETIMEs > comparison in some cases. > > Fix: comparing DATETIMEs as strings we must trim trailing 0's > in such cases. > ------------------------------------------------------------ > Use --include-merges or -n0 to see merged revisions. --- mysql-test/r/innodb_mysql.result | 42 ++++++++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 29 ++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index b112bde4f27..c882d2af1ed 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -2209,4 +2209,46 @@ EXPLAIN SELECT * FROM t1 FORCE INDEX(PRIMARY) WHERE b=1 AND c=1 ORDER BY a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 128 Using where DROP TABLE t1; +# +# Bug #47963: Wrong results when index is used +# +CREATE TABLE t1( +a VARCHAR(5) NOT NULL, +b VARCHAR(5) NOT NULL, +c DATETIME NOT NULL, +KEY (c) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES('TEST', 'TEST', '2009-10-09 00:00:00'); +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00.0'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00.0'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.000' AND c <= '2009-10-09 00:00:00.000'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.00' AND c <= '2009-10-09 00:00:00.001'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +a b c +EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index c643465b2f3..7055879ce1a 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -461,4 +461,33 @@ EXPLAIN SELECT * FROM t1 FORCE INDEX(PRIMARY) WHERE b=1 AND c=1 ORDER BY a; DROP TABLE t1; +--echo # +--echo # Bug #47963: Wrong results when index is used +--echo # +CREATE TABLE t1( + a VARCHAR(5) NOT NULL, + b VARCHAR(5) NOT NULL, + c DATETIME NOT NULL, + KEY (c) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES('TEST', 'TEST', '2009-10-09 00:00:00'); +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00.0'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00.0'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.000' AND c <= '2009-10-09 00:00:00.000'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.00' AND c <= '2009-10-09 00:00:00.001'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +DROP TABLE t1; + + --echo End of 5.1 tests From 57ca07a5e9e49ce416c718e796283b69a835fa23 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:16:26 +0100 Subject: [PATCH 16/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3184.3.13 > revision-id: joro@sun.com-20091019135504-e6fmhf4xyy0wdymb > parent: joro@sun.com-20091026095557-euhe1z9oxtgkw35h > committer: Georgi Kodinov > branch nick: B47788-5.1-bugteam > timestamp: Mon 2009-10-19 16:55:04 +0300 > message: > Bug #47788: Crash in TABLE_LIST::hide_view_error on > UPDATE + VIEW + SP + MERGE + ALTER > > When cleaning up the stored procedure's internal > structures the flag to ignore the errors for > INSERT/UPDATE IGNORE was not cleaned up. > As a result error ignoring was on during name > resolution. And this is an abnormal situation : the > SELECT_LEX flag can be on only during query execution. > > Fixed by correctly cleaning up the SELECT_LEX flag > when reusing the SELECT_LEX in a second execution. --- mysql-test/r/sp-error.result | 16 ++++++++++++++++ mysql-test/t/sp-error.test | 24 ++++++++++++++++++++++++ sql/sql_prepare.cc | 3 +++ 3 files changed, 43 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 17ab2b79043..b3968ea7eb6 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1670,3 +1670,19 @@ NULL SELECT non_existent (a) FROM t1 WHERE b = 999999; ERROR 42000: FUNCTION test.non_existent does not exist DROP TABLE t1; +# +# Bug #47788: Crash in TABLE_LIST::hide_view_error on UPDATE + VIEW + +# SP + MERGE + ALTER +# +CREATE TABLE t1 (pk INT, b INT, KEY (b)); +CREATE ALGORITHM = TEMPTABLE VIEW v1 AS SELECT * FROM t1; +CREATE PROCEDURE p1 (a int) UPDATE IGNORE v1 SET b = a; +CALL p1(5); +ERROR HY000: The target table v1 of the UPDATE is not updatable +ALTER TABLE t1 CHANGE COLUMN b b2 INT; +CALL p1(7); +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 66b960c938f..18a4a117939 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2448,3 +2448,27 @@ SELECT AVG (a) FROM t1 WHERE b = 999999; --error ER_SP_DOES_NOT_EXIST SELECT non_existent (a) FROM t1 WHERE b = 999999; DROP TABLE t1; + +--echo # +--echo # Bug #47788: Crash in TABLE_LIST::hide_view_error on UPDATE + VIEW + +--echo # SP + MERGE + ALTER +--echo # + +CREATE TABLE t1 (pk INT, b INT, KEY (b)); +CREATE ALGORITHM = TEMPTABLE VIEW v1 AS SELECT * FROM t1; + +CREATE PROCEDURE p1 (a int) UPDATE IGNORE v1 SET b = a; + +--error ER_NON_UPDATABLE_TABLE +CALL p1(5); + +ALTER TABLE t1 CHANGE COLUMN b b2 INT; + +--error ER_VIEW_INVALID +CALL p1(7); + +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c1839b7220f..7c618ac4b37 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2342,6 +2342,9 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) /* Fix ORDER list */ for (order= (ORDER *)sl->order_list.first; order; order= order->next) order->item= &order->item_ptr; + + /* clear the no_error flag for INSERT/UPDATE IGNORE */ + sl->no_error= FALSE; } { SELECT_LEX_UNIT *unit= sl->master_unit(); From dda43d98d36bd1f9a0a38d1cb64b716dae4d0c49 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:17:57 +0100 Subject: [PATCH 17/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3184.7.1 > revision-id: luis.soares@sun.com-20091027151553-ri74b2zdchw8wyg7 > parent: joro@sun.com-20091019135504-e6fmhf4xyy0wdymb > committer: Luis Soares > branch nick: mysql-5.1-bugteam > timestamp: Tue 2009-10-27 15:15:53 +0000 > message: > BUG#48297: Schema name is ignored when LOAD DATA is written into > binlog, replication aborts > > In SBR or MBR, the schema name is not being written to the binlog > when executing a LOAD DATA statement. This becomes a problem when > the current database (lets call it db1) is different from the > table's schema (lets call it db2). For instance, take the > following statements: > > use db1; > load data local infile 'infile.txt' into table db2.t > > Should this statement be logged without t's schema (db2), when > replaying it, one can get db1.t populated instead of db2.t (if > db1.t exists). On the other hand, if there is no db1.t at all, > replication will stop. > > We fix this by always logging the table (in load file) with fully > qualified name when its schema is different from the current > database or when no default database was selected. --- mysql-test/extra/rpl_tests/rpl_loaddata.test | 61 ++++++++++++++++++++ mysql-test/suite/rpl/r/rpl_loaddata.result | 29 ++++++++++ sql/sql_load.cc | 30 ++++++++-- 3 files changed, 115 insertions(+), 5 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_loaddata.test b/mysql-test/extra/rpl_tests/rpl_loaddata.test index 26916642cae..7db12600456 100644 --- a/mysql-test/extra/rpl_tests/rpl_loaddata.test +++ b/mysql-test/extra/rpl_tests/rpl_loaddata.test @@ -158,4 +158,65 @@ LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1; DROP TABLE IF EXISTS t1; +# BUG#48297: Schema name is ignored when LOAD DATA is written into binlog, +# replication aborts +-- source include/master-slave-reset.inc + +-- let $db1= b48297_db1 +-- let $db2= b42897_db2 + +-- connection master + +-- disable_warnings +-- eval drop database if exists $db1 +-- eval drop database if exists $db2 +-- enable_warnings + +-- eval create database $db1 +-- eval create database $db2 + +-- eval use $db1 +-- eval CREATE TABLE t1 (c1 VARCHAR(256)) engine=$engine_type; + +-- eval use $db2 + +-- echo ### assertion: works with cross-referenced database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 + +-- eval use $db1 +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- echo ### assertion: works with fully qualified name on current database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 + +-- echo ### assertion: works without fully qualified name on current database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1 + +-- echo ### create connection without default database +-- echo ### connect (conn2,localhost,root,,*NO-ONE*); +connect (conn2,localhost,root,,*NO-ONE*); +-- connection conn2 +-- echo ### assertion: works without stating the default database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 +-- echo ### disconnect and switch back to master connection +-- disconnect conn2 +-- connection master + +-- sync_slave_with_master +-- eval use $db1 + +let $diff_table_1=master:$db1.t1; +let $diff_table_2=slave:$db1.t1; +source include/diff_tables.inc; + +-- connection master + +-- eval DROP DATABASE $db1 +-- eval DROP DATABASE $db2 + +-- sync_slave_with_master + # End of 4.1 tests diff --git a/mysql-test/suite/rpl/r/rpl_loaddata.result b/mysql-test/suite/rpl/r/rpl_loaddata.result index 0653936f0ec..ca9c14691b0 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata.result @@ -86,3 +86,32 @@ CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB; LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1; ERROR 23000: Duplicate entry 'Aarhus' for key 'PRIMARY' DROP TABLE IF EXISTS t1; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop database if exists b48297_db1; +drop database if exists b42897_db2; +create database b48297_db1; +create database b42897_db2; +use b48297_db1; +CREATE TABLE t1 (c1 VARCHAR(256)) engine=MyISAM;; +use b42897_db2; +### assertion: works with cross-referenced database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +use b48297_db1; +### assertion: works with fully qualified name on current database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +### assertion: works without fully qualified name on current database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1; +### create connection without default database +### connect (conn2,localhost,root,,*NO-ONE*); +### assertion: works without stating the default database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +### disconnect and switch back to master connection +use b48297_db1; +Comparing tables master:b48297_db1.t1 and slave:b48297_db1.t1 +DROP DATABASE b48297_db1; +DROP DATABASE b42897_db2; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index e830e29176b..238678ef9bc 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -84,7 +84,7 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, bool ignore_check_option_errors); #ifndef EMBEDDED_LIBRARY static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, - const char* db_arg, + const char* db_arg, /* table's database */ const char* table_name_arg, enum enum_duplicates duplicates, bool ignore, @@ -501,7 +501,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, ex, - tdb, table_list->table_name, + table_list->db, + table_list->table_name, handle_duplicates, ignore, transactional_table, errcode); @@ -548,7 +549,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); write_execute_load_query_log_event(thd, ex, - tdb, table_list->table_name, + table_list->db, table_list->table_name, handle_duplicates, ignore, transactional_table, errcode); @@ -573,7 +574,7 @@ err: /* Not a very useful function; just to avoid duplication of code */ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, - const char* db_arg, + const char* db_arg, /* table's database */ const char* table_name_arg, enum enum_duplicates duplicates, bool ignore, @@ -590,8 +591,27 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, Item *item, *val; String pfield, pfields; int n; + const char *tbl= table_name_arg; + const char *tdb= (thd->db != NULL ? thd->db : db_arg); + String string_buf; - Load_log_event lle(thd, ex, db_arg, table_name_arg, fv, duplicates, + if (!thd->db || strcmp(db_arg, thd->db)) + { + /* + If used database differs from table's database, + prefix table name with database name so that it + becomes a FQ name. + */ + string_buf.set_charset(system_charset_info); + string_buf.append(db_arg); + string_buf.append("`"); + string_buf.append("."); + string_buf.append("`"); + string_buf.append(table_name_arg); + tbl= string_buf.c_ptr_safe(); + } + + Load_log_event lle(thd, ex, tdb, tbl, fv, duplicates, ignore, transactional_table); /* From dee8224be7394e32d2c7deb1d2ae5a9537186289 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:18:52 +0100 Subject: [PATCH 18/35] Backport into build-200911241145-5.1.40sp1 > ------------------------------------------------------------ > revno: 3190 [merge] > revision-id: kostja@sun.com-20091103174552-bfpak6r7ngf5cbjb > parent: magnus.blaudd@sun.com-20091103170719-6b64sjnivsiyz6xy > parent: kostja@sun.com-20091103165854-7di545xruez8w207 > committer: Konstantin Osipov > branch nick: 5.1-41756 > timestamp: Tue 2009-11-03 20:45:52 +0300 > message: > A fix and a test case for > Bug#41756 "Strange error messages about locks from InnoDB". > > In JT_EQ_REF (join_read_key()) access method, > don't try to unlock rows in the handler, unless certain that > a) they were locked > b) they are not used. > > Unlocking of rows is done by the logic of the nested join loop, > and is unaware of the possible caching that the access method may > have. This could lead to double unlocking, when a row > was unlocked first after reading into the cache, and then > when taken from cache, as well as to unlocking of rows which > were actually used (but taken from cache). > > Delegate part of the unlocking logic to the access method, > and in JT_EQ_REF count how many times a record was actually > used in the join. Unlock it only if it's usage count is 0. > > Implemented review comments. > ------------------------------------------------------------ > Use --include-merges or -n0 to see merged revisions. --- sql/item_subselect.cc | 1 + sql/records.cc | 2 ++ sql/sql_select.cc | 60 +++++++++++++++++++++++++++++++++++++++++-- sql/sql_select.h | 7 +++++ sql/structs.h | 14 +++++++--- 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 29db9eb0903..fa776ea3dca 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1954,6 +1954,7 @@ int subselect_single_select_engine::exec() tab->read_record.record= tab->table->record[0]; tab->read_record.thd= join->thd; tab->read_record.ref_length= tab->table->file->ref_length; + tab->read_record.unlock_row= rr_unlock_row; *(last_changed_tab++)= tab; break; } diff --git a/sql/records.cc b/sql/records.cc index 9e040de3fda..ed927ac3bc8 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -61,6 +61,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, info->file= table->file; info->record= table->record[0]; info->print_error= print_error; + info->unlock_row= rr_unlock_row; table->status=0; /* And it's always found */ if (!table->file->inited) @@ -186,6 +187,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, } info->select=select; info->print_error=print_error; + info->unlock_row= rr_unlock_row; info->ignore_not_found_rows= 0; table->status=0; /* And it's always found */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 34d23ace89b..c230363a045 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -149,6 +149,7 @@ static int join_read_const_table(JOIN_TAB *tab, POSITION *pos); static int join_read_system(JOIN_TAB *tab); static int join_read_const(JOIN_TAB *tab); static int join_read_key(JOIN_TAB *tab); +static void join_read_key_unlock_row(st_join_table *tab); static int join_read_always_key(JOIN_TAB *tab); static int join_read_last_key(JOIN_TAB *tab); static int join_no_more_records(READ_RECORD *info); @@ -5607,7 +5608,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, } j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length); j->ref.key_err=1; + j->ref.has_record= FALSE; j->ref.null_rejecting= 0; + j->ref.use_count= 0; keyuse=org_keyuse; store_key **ref_key= j->ref.key_copy; @@ -6440,6 +6443,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) DBUG_RETURN(0); } + +/** + The default implementation of unlock-row method of READ_RECORD, + used in all access methods. +*/ + +void rr_unlock_row(st_join_table *tab) +{ + READ_RECORD *info= &tab->read_record; + info->file->unlock_row(); +} + + + static void make_join_readinfo(JOIN *join, ulonglong options) { @@ -6455,6 +6472,7 @@ make_join_readinfo(JOIN *join, ulonglong options) TABLE *table=tab->table; tab->read_record.table= table; tab->read_record.file=table->file; + tab->read_record.unlock_row= rr_unlock_row; tab->next_select=sub_select; /* normal select */ /* @@ -6500,6 +6518,7 @@ make_join_readinfo(JOIN *join, ulonglong options) delete tab->quick; tab->quick=0; tab->read_first_record= join_read_key; + tab->read_record.unlock_row= join_read_key_unlock_row; tab->read_record.read_record= join_no_more_records; if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) @@ -11327,7 +11346,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_NO_MORE_ROWS; } else - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } else { @@ -11337,7 +11356,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, */ join->examined_rows++; join->thd->row_count++; - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } return NESTED_LOOP_OK; } @@ -11697,18 +11716,55 @@ join_read_key(JOIN_TAB *tab) table->status=STATUS_NOT_FOUND; return -1; } + /* + Moving away from the current record. Unlock the row + in the handler if it did not match the partial WHERE. + */ + if (tab->ref.has_record && tab->ref.use_count == 0) + { + tab->read_record.file->unlock_row(); + tab->ref.has_record= FALSE; + } error=table->file->index_read_map(table->record[0], tab->ref.key_buff, make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); + + if (! error) + { + tab->ref.has_record= TRUE; + tab->ref.use_count= 1; + } + } + else if (table->status == 0) + { + DBUG_ASSERT(tab->ref.has_record); + tab->ref.use_count++; } table->null_row=0; return table->status ? -1 : 0; } +/** + Since join_read_key may buffer a record, do not unlock + it if it was not used in this invocation of join_read_key(). + Only count locks, thus remembering if the record was left unused, + and unlock already when pruning the current value of + TABLE_REF buffer. + @sa join_read_key() +*/ + +static void +join_read_key_unlock_row(st_join_table *tab) +{ + DBUG_ASSERT(tab->ref.use_count); + if (tab->ref.use_count) + tab->ref.use_count--; +} + /* ref access method implementation: "read_first" function diff --git a/sql/sql_select.h b/sql/sql_select.h index 4c729fa915c..991bc900df0 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -58,6 +58,8 @@ class store_key; typedef struct st_table_ref { bool key_err; + /** True if something was read into buffer in join_read_key. */ + bool has_record; uint key_parts; ///< num of ... uint key_length; ///< length of key_buff int key; ///< key no @@ -85,6 +87,11 @@ typedef struct st_table_ref table_map depend_map; ///< Table depends on these tables. /* null byte position in the key_buf. Used for REF_OR_NULL optimization */ uchar *null_ref_key; + /* + The number of times the record associated with this key was used + in the join. + */ + ha_rows use_count; } TABLE_REF; diff --git a/sql/structs.h b/sql/structs.h index a58c18f97c5..2546d241059 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -115,16 +115,22 @@ typedef struct st_reginfo { /* Extra info about reg */ } REGINFO; -struct st_read_record; /* For referense later */ class SQL_SELECT; class THD; class handler; +struct st_join_table; -typedef struct st_read_record { /* Parameter to read_record */ +void rr_unlock_row(st_join_table *tab); + +struct READ_RECORD { /* Parameter to read_record */ + typedef int (*Read_func)(READ_RECORD*); + typedef void (*Unlock_row_func)(st_join_table *); struct st_table *table; /* Head-form */ handler *file; struct st_table **forms; /* head and ref forms */ - int (*read_record)(struct st_read_record *); + + Read_func read_record; + Unlock_row_func unlock_row; THD *thd; SQL_SELECT *select; uint cache_records; @@ -136,7 +142,7 @@ typedef struct st_read_record { /* Parameter to read_record */ uchar *cache,*cache_pos,*cache_end,*read_positions; IO_CACHE *io_cache; bool print_error, ignore_not_found_rows; -} READ_RECORD; +}; /* From 9c62fbffbde015a6f7e85829c684c659a8f1236c Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 18:21:48 +0100 Subject: [PATCH 19/35] Test cases added --- mysql-test/r/innodb_bug47777.result | 13 + .../r/innodb_lock_wait_timeout_1.result | 308 ++++++++++++++++++ mysql-test/t/innodb_bug47777.test | 24 ++ .../t/innodb_lock_wait_timeout_1-master.opt | 1 + mysql-test/t/innodb_lock_wait_timeout_1.test | 160 +++++++++ 5 files changed, 506 insertions(+) create mode 100644 mysql-test/r/innodb_bug47777.result create mode 100644 mysql-test/r/innodb_lock_wait_timeout_1.result create mode 100644 mysql-test/t/innodb_bug47777.test create mode 100644 mysql-test/t/innodb_lock_wait_timeout_1-master.opt create mode 100644 mysql-test/t/innodb_lock_wait_timeout_1.test diff --git a/mysql-test/r/innodb_bug47777.result b/mysql-test/r/innodb_bug47777.result new file mode 100644 index 00000000000..fbba47edcfc --- /dev/null +++ b/mysql-test/r/innodb_bug47777.result @@ -0,0 +1,13 @@ +create table bug47777(c2 linestring not null, primary key (c2(1))) engine=innodb; +insert into bug47777 values (geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)')); +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); +count(*) +1 +update bug47777 set c2=GeomFromText('POINT(1 1)'); +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); +count(*) +0 +select count(*) from bug47777 where c2 = GeomFromText('POINT(1 1)'); +count(*) +1 +drop table bug47777; diff --git a/mysql-test/r/innodb_lock_wait_timeout_1.result b/mysql-test/r/innodb_lock_wait_timeout_1.result new file mode 100644 index 00000000000..f331d3acd27 --- /dev/null +++ b/mysql-test/r/innodb_lock_wait_timeout_1.result @@ -0,0 +1,308 @@ +# +# Bug#41756 Strange error messages about locks from InnoDB +# +drop table if exists t1; +# In the default transaction isolation mode, and/or with +# innodb_locks_unsafe_for_binlog=OFF, handler::unlock_row() +# in InnoDB does nothing. +# Thus in order to reproduce the condition that led to the +# warning, one needs to relax isolation by either +# setting a weaker tx_isolation value, or by turning on +# the unsafe replication switch. +# For testing purposes, choose to tweak the isolation level, +# since it's settable at runtime, unlike +# innodb_locks_unsafe_for_binlog, which is +# only a command-line switch. +# +set @@session.tx_isolation="read-committed"; +# Prepare data. We need a table with a unique index, +# for join_read_key to be used. The other column +# allows to control what passes WHERE clause filter. +create table t1 (a int primary key, b int) engine=innodb; +# Let's make sure t1 has sufficient amount of rows +# to exclude JT_ALL access method when reading it, +# i.e. make sure that JT_EQ_REF(a) is always preferred. +insert into t1 values (1,1), (2,null), (3,1), (4,1), +(5,1), (6,1), (7,1), (8,1), (9,1), (10,1), +(11,1), (12,1), (13,1), (14,1), (15,1), +(16,1), (17,1), (18,1), (19,1), (20,1); +# +# Demonstrate that for the SELECT statement +# used later in the test JT_EQ_REF access method is used. +# +explain +select 1 from t1 natural join (select 2 as a, 1 as b union all +select 2 as a, 2 as b) as t2 for update; +id 1 +select_type PRIMARY +table +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows 2 +Extra +id 1 +select_type PRIMARY +table t1 +type eq_ref +possible_keys PRIMARY +key PRIMARY +key_len 4 +ref t2.a +rows 1 +Extra Using where +id 2 +select_type DERIVED +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id 3 +select_type UNION +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id NULL +select_type UNION RESULT +table +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra +# +# Demonstrate that the reported SELECT statement +# no longer produces warnings. +# +select 1 from t1 natural join (select 2 as a, 1 as b union all +select 2 as a, 2 as b) as t2 for update; +1 +commit; +# +# Demonstrate that due to lack of inter-sweep "reset" function, +# we keep some non-matching records locked, even though we know +# we could unlock them. +# To do that, show that if there is only one distinct value +# for a in t2 (a=2), we will keep record (2,null) in t1 locked. +# But if we add another value for "a" to t2, say 6, +# join_read_key cache will be pruned at least once, +# and thus record (2, null) in t1 will get unlocked. +# +begin; +select 1 from t1 natural join (select 2 as a, 1 as b union all +select 2 as a, 2 as b) as t2 for update; +1 +# +# Switching to connection con1 +# We should be able to delete all records from t1 except (2, null), +# since they were not locked. +begin; +# Delete in series of 3 records so that full scan +# is not used and we're not blocked on record (2,null) +delete from t1 where a in (1,3,4); +delete from t1 where a in (5,6,7); +delete from t1 where a in (8,9,10); +delete from t1 where a in (11,12,13); +delete from t1 where a in (14,15,16); +delete from t1 where a in (17,18); +delete from t1 where a in (19,20); +# +# Record (2, null) is locked. This is actually unnecessary, +# because the previous select returned no rows. +# Just demonstrate the effect. +# +delete from t1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +# +# Switching to connection default +# +# Show that the original contents of t1 is intact: +select * from t1; +a b +1 1 +2 NULL +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +commit; +# +# Have a one more record in t2 to show that +# if join_read_key cache is purned, the current +# row under the cursor is unlocked (provided, this row didn't +# match the partial WHERE clause, of course). +# Sic: the result of this test dependent on the order of retrieval +# of records --echo # from the derived table, if ! +# We use DELETE to disable the JOIN CACHE. This DELETE modifies no +# records. It also should leave no InnoDB row locks. +# +begin; +delete t1.* from t1 natural join (select 2 as a, 2 as b union all +select 0 as a, 0 as b) as t2; +# Demonstrate that nothing was deleted form t1 +select * from t1; +a b +1 1 +2 NULL +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +# +# Switching to connection con1 +begin; +# Since there is another distinct record in the derived table +# the previous matching record in t1 -- (2,null) -- was unlocked. +delete from t1; +# We will need the contents of the table again. +rollback; +select * from t1; +a b +1 1 +2 NULL +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +commit; +# +# Switching to connection default +rollback; +begin; +# +# Before this patch, we could wrongly unlock a record +# that was cached and later used in a join. Demonstrate that +# this is no longer the case. +# Sic: this test is also order-dependent (i.e. the +# the bug would show up only if the first record in the union +# is retreived and processed first. +# +# Verify that JT_EQ_REF is used. +explain +select 1 from t1 natural join (select 3 as a, 2 as b union all +select 3 as a, 1 as b) as t2 for update; +id 1 +select_type PRIMARY +table +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows 2 +Extra +id 1 +select_type PRIMARY +table t1 +type eq_ref +possible_keys PRIMARY +key PRIMARY +key_len 4 +ref t2.a +rows 1 +Extra Using where +id 2 +select_type DERIVED +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id 3 +select_type UNION +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id NULL +select_type UNION RESULT +table +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra +# Lock the record. +select 1 from t1 natural join (select 3 as a, 2 as b union all +select 3 as a, 1 as b) as t2 for update; +1 +1 +# Switching to connection con1 +# +# We should not be able to delete record (3,1) from t1, +# (previously it was possible). +# +delete from t1 where a=3; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +# Switching to connection default +commit; +set @@session.tx_isolation=default; +drop table t1; +# +# End of 5.1 tests +# diff --git a/mysql-test/t/innodb_bug47777.test b/mysql-test/t/innodb_bug47777.test new file mode 100644 index 00000000000..8f2985b2cf0 --- /dev/null +++ b/mysql-test/t/innodb_bug47777.test @@ -0,0 +1,24 @@ +# This is the test for bug 47777. GEOMETRY +# data is treated as BLOB data in innodb. +# Consequently, its key value generation/storing +# should follow the process for the BLOB +# datatype as well. + +--source include/have_innodb.inc + +create table bug47777(c2 linestring not null, primary key (c2(1))) engine=innodb; + +insert into bug47777 values (geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)')); + +# Verify correct row get inserted. +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); + +# Update table bug47777 should be successful. +update bug47777 set c2=GeomFromText('POINT(1 1)'); + +# Verify the row get updated successfully. The original +# c2 value should be changed to GeomFromText('POINT(1 1)'). +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); +select count(*) from bug47777 where c2 = GeomFromText('POINT(1 1)'); + +drop table bug47777; diff --git a/mysql-test/t/innodb_lock_wait_timeout_1-master.opt b/mysql-test/t/innodb_lock_wait_timeout_1-master.opt new file mode 100644 index 00000000000..462f8fbe828 --- /dev/null +++ b/mysql-test/t/innodb_lock_wait_timeout_1-master.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=1 diff --git a/mysql-test/t/innodb_lock_wait_timeout_1.test b/mysql-test/t/innodb_lock_wait_timeout_1.test new file mode 100644 index 00000000000..ecb7aff4598 --- /dev/null +++ b/mysql-test/t/innodb_lock_wait_timeout_1.test @@ -0,0 +1,160 @@ +--source include/have_innodb.inc + +--echo # +--echo # Bug#41756 Strange error messages about locks from InnoDB +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +--echo # In the default transaction isolation mode, and/or with +--echo # innodb_locks_unsafe_for_binlog=OFF, handler::unlock_row() +--echo # in InnoDB does nothing. +--echo # Thus in order to reproduce the condition that led to the +--echo # warning, one needs to relax isolation by either +--echo # setting a weaker tx_isolation value, or by turning on +--echo # the unsafe replication switch. +--echo # For testing purposes, choose to tweak the isolation level, +--echo # since it's settable at runtime, unlike +--echo # innodb_locks_unsafe_for_binlog, which is +--echo # only a command-line switch. +--echo # +set @@session.tx_isolation="read-committed"; + +--echo # Prepare data. We need a table with a unique index, +--echo # for join_read_key to be used. The other column +--echo # allows to control what passes WHERE clause filter. +create table t1 (a int primary key, b int) engine=innodb; +--echo # Let's make sure t1 has sufficient amount of rows +--echo # to exclude JT_ALL access method when reading it, +--echo # i.e. make sure that JT_EQ_REF(a) is always preferred. +insert into t1 values (1,1), (2,null), (3,1), (4,1), + (5,1), (6,1), (7,1), (8,1), (9,1), (10,1), + (11,1), (12,1), (13,1), (14,1), (15,1), + (16,1), (17,1), (18,1), (19,1), (20,1); +--echo # +--echo # Demonstrate that for the SELECT statement +--echo # used later in the test JT_EQ_REF access method is used. +--echo # +--vertical_results +explain +select 1 from t1 natural join (select 2 as a, 1 as b union all + select 2 as a, 2 as b) as t2 for update; +--horizontal_results +--echo # +--echo # Demonstrate that the reported SELECT statement +--echo # no longer produces warnings. +--echo # +select 1 from t1 natural join (select 2 as a, 1 as b union all + select 2 as a, 2 as b) as t2 for update; +commit; +--echo # +--echo # Demonstrate that due to lack of inter-sweep "reset" function, +--echo # we keep some non-matching records locked, even though we know +--echo # we could unlock them. +--echo # To do that, show that if there is only one distinct value +--echo # for a in t2 (a=2), we will keep record (2,null) in t1 locked. +--echo # But if we add another value for "a" to t2, say 6, +--echo # join_read_key cache will be pruned at least once, +--echo # and thus record (2, null) in t1 will get unlocked. +--echo # +begin; +select 1 from t1 natural join (select 2 as a, 1 as b union all + select 2 as a, 2 as b) as t2 for update; +connect (con1,localhost,root,,); +--echo # +--echo # Switching to connection con1 +connection con1; +--echo # We should be able to delete all records from t1 except (2, null), +--echo # since they were not locked. +begin; +--echo # Delete in series of 3 records so that full scan +--echo # is not used and we're not blocked on record (2,null) +delete from t1 where a in (1,3,4); +delete from t1 where a in (5,6,7); +delete from t1 where a in (8,9,10); +delete from t1 where a in (11,12,13); +delete from t1 where a in (14,15,16); +delete from t1 where a in (17,18); +delete from t1 where a in (19,20); +--echo # +--echo # Record (2, null) is locked. This is actually unnecessary, +--echo # because the previous select returned no rows. +--echo # Just demonstrate the effect. +--echo # +--error ER_LOCK_WAIT_TIMEOUT +delete from t1; +rollback; +--echo # +--echo # Switching to connection default +connection default; +--echo # +--echo # Show that the original contents of t1 is intact: +select * from t1; +commit; +--echo # +--echo # Have a one more record in t2 to show that +--echo # if join_read_key cache is purned, the current +--echo # row under the cursor is unlocked (provided, this row didn't +--echo # match the partial WHERE clause, of course). +--echo # Sic: the result of this test dependent on the order of retrieval +--echo # of records --echo # from the derived table, if ! +--echo # We use DELETE to disable the JOIN CACHE. This DELETE modifies no +--echo # records. It also should leave no InnoDB row locks. +--echo # +begin; +delete t1.* from t1 natural join (select 2 as a, 2 as b union all + select 0 as a, 0 as b) as t2; +--echo # Demonstrate that nothing was deleted form t1 +select * from t1; +--echo # +--echo # Switching to connection con1 +connection con1; +begin; +--echo # Since there is another distinct record in the derived table +--echo # the previous matching record in t1 -- (2,null) -- was unlocked. +delete from t1; +--echo # We will need the contents of the table again. +rollback; +select * from t1; +commit; +--echo # +--echo # Switching to connection default +connection default; +rollback; +begin; +--echo # +--echo # Before this patch, we could wrongly unlock a record +--echo # that was cached and later used in a join. Demonstrate that +--echo # this is no longer the case. +--echo # Sic: this test is also order-dependent (i.e. the +--echo # the bug would show up only if the first record in the union +--echo # is retreived and processed first. +--echo # +--echo # Verify that JT_EQ_REF is used. +--vertical_results +explain +select 1 from t1 natural join (select 3 as a, 2 as b union all + select 3 as a, 1 as b) as t2 for update; +--horizontal_results +--echo # Lock the record. +select 1 from t1 natural join (select 3 as a, 2 as b union all + select 3 as a, 1 as b) as t2 for update; +--echo # Switching to connection con1 +connection con1; +--echo # +--echo # We should not be able to delete record (3,1) from t1, +--echo # (previously it was possible). +--echo # +--error ER_LOCK_WAIT_TIMEOUT +delete from t1 where a=3; +--echo # Switching to connection default +connection default; +commit; + +disconnect con1; +set @@session.tx_isolation=default; +drop table t1; + +--echo # +--echo # End of 5.1 tests +--echo # From 597f8d5e350237a29bc1d8cbf872079e30698920 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 23:24:18 +0100 Subject: [PATCH 20/35] Patch adjustments --- mysql-test/r/range.result | 6 +++--- mysql-test/t/range.test | 5 ++--- storage/innodb_plugin/handler/ha_innodb.cc | 5 ++++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 3ed2c3f53d0..3b4870ad89c 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1216,6 +1216,9 @@ select 'In following EXPLAIN the access method should be ref, #rows~=500 (and no Z In following EXPLAIN the access method should be ref, #rows~=500 (and not 2) explain select * from t2 where a=1000 and b<11; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref a a 5 const 502 Using where +drop table t1, t2; # # Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN # @@ -1224,9 +1227,6 @@ INSERT INTO t1 VALUES (1), (NULL); SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); a DROP TABLE t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ref a a 5 const 502 Using where -drop table t1, t2; # # Bug#47925: regression of range optimizer and date comparison in 5.1.39! # diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 272df5f272e..5f53fafc5b4 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1043,6 +1043,8 @@ alter table t2 add index (a,b); select 'In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)' Z; explain select * from t2 where a=1000 and b<11; +drop table t1, t2; + --echo # --echo # Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN --echo # @@ -1052,9 +1054,6 @@ INSERT INTO t1 VALUES (1), (NULL); SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); DROP TABLE t1; - -drop table t1, t2; - --echo # --echo # Bug#47925: regression of range optimizer and date comparison in 5.1.39! --echo # diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 682004407c7..f01ff4450c8 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -3704,7 +3704,10 @@ ha_innobase::store_key_val_for_row( } else if (mysql_type == MYSQL_TYPE_TINY_BLOB || mysql_type == MYSQL_TYPE_MEDIUM_BLOB || mysql_type == MYSQL_TYPE_BLOB - || mysql_type == MYSQL_TYPE_LONG_BLOB) { + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { CHARSET_INFO* cs; ulint key_len; From 493c0553df830bf3f949c689d3123b6a0c2afcef Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 25 Nov 2009 23:43:37 +0100 Subject: [PATCH 21/35] Patch adjustments --- storage/innodb_plugin/handler/ha_innodb.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index f01ff4450c8..3fb81be031d 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -8679,6 +8679,7 @@ ha_innobase::get_auto_increment( AUTOINC counter after attempting to insert the row. */ if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) { ulonglong need; + ulonglong current; ulonglong next_value; ulonglong col_max_value; @@ -8687,11 +8688,12 @@ ha_innobase::get_auto_increment( col_max_value = innobase_get_int_col_max_value( table->next_number_field); + current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; /* Compute the last value in the interval */ next_value = innobase_next_autoinc( - *first_value, need, offset, col_max_value); + current, need, offset, col_max_value); prebuilt->autoinc_last_value = next_value; From 3b5b82eea3ebfaecdcb0a941216e0a1c67f4d3f1 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 2 Dec 2009 09:58:30 +0200 Subject: [PATCH 22/35] tree name change to -main --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 557df1b1ffe..f79c1cd6319 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.0-bugteam" +tree_name = "mysql-5.0" From 317d0f76b65699ab5f0d02b9061f60741bc52d5c Mon Sep 17 00:00:00 2001 From: Satya B Date: Wed, 2 Dec 2009 15:17:49 +0530 Subject: [PATCH 23/35] Disable the test case innodb-autonic.test until BUG#49267 is fixed Add the test to disabled list and remove from the experimental list. --- mysql-test/collections/default.experimental | 1 - mysql-test/t/disabled.def | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 49a0fd8c58c..5f3b7251ce1 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -13,7 +13,6 @@ funcs_1.ndb* # joro : NDB tests marked as experiment funcs_2.ndb_charset # joro : NDB tests marked as experimental as agreed with bochklin main.ctype_gbk_binlog @solaris # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists -main.innodb-autoinc* # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin main.plugin_load @solaris # Bug#42144 ndb.* # joro : NDB tests marked as experimental as agreed with bochklin diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 06d3dbb4e57..378b810fcbb 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -12,3 +12,4 @@ kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild. query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically rpl_killed_ddl : Bug#45520: rpl_killed_ddl fails sporadically in pb2 +innodb-autoinc : Bug#49267 2009-12-02 test fails on windows because of different case mode From 032f88055e51240f2f68b8fbbbc563877713880b Mon Sep 17 00:00:00 2001 From: "karen.langford@sun.com" <> Date: Wed, 2 Dec 2009 18:52:19 +0100 Subject: [PATCH 24/35] Raise version number after cloning 5.1.42 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 79138561dcb..8107884ec3c 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.42) +AM_INIT_AUTOMAKE(mysql, 5.1.43) AM_CONFIG_HEADER([include/config.h:config.h.in]) # Request support for automake silent-rules if available. From d4d4e38413b62db48450025f1f0bfc259cd5e639 Mon Sep 17 00:00:00 2001 From: "karen.langford@sun.com" <> Date: Tue, 8 Dec 2009 16:35:00 +0100 Subject: [PATCH 25/35] Raise version number after cloning 5.0.89 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index e14b4014bea..b206dfbd079 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.89) +AM_INIT_AUTOMAKE(mysql, 5.0.90) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=89 +NDB_VERSION_BUILD=90 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 4b603e488125e0bae275936bb35208bb3ddde90a Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 Dec 2009 10:37:10 +0200 Subject: [PATCH 26/35] Bug #49480: WHERE using YEAR columns returns unexpected results Merge the fix from 5.1-bugteam to 5.1-main --- mysql-test/r/type_year.result | 264 ++++++++++++++++++++++++++++++++++ mysql-test/t/type_year.test | 106 ++++++++++++++ sql/item_cmpfunc.cc | 144 +++++++------------ sql/item_cmpfunc.h | 9 +- 4 files changed, 421 insertions(+), 102 deletions(-) diff --git a/mysql-test/r/type_year.result b/mysql-test/r/type_year.result index e52947455c8..56b326327c6 100644 --- a/mysql-test/r/type_year.result +++ b/mysql-test/r/type_year.result @@ -46,3 +46,267 @@ a 2001 drop table t1; End of 5.0 tests +# +# Bug #49480: WHERE using YEAR columns returns unexpected results +# +CREATE TABLE t2(yy YEAR(2), c2 CHAR(4)); +CREATE TABLE t4(yyyy YEAR(4), c4 CHAR(4)); +INSERT INTO t2 (c2) VALUES (NULL),(1970),(1999),(2000),(2001),(2069); +INSERT INTO t4 (c4) SELECT c2 FROM t2; +UPDATE t2 SET yy = c2; +UPDATE t4 SET yyyy = c4; +SELECT * FROM t2; +yy c2 +NULL NULL +70 1970 +99 1999 +00 2000 +01 2001 +69 2069 +SELECT * FROM t4; +yyyy c4 +NULL NULL +1970 1970 +1999 1999 +2000 2000 +2001 2001 +2069 2069 +# Comparison of YEAR(2) with YEAR(4) +SELECT * FROM t2, t4 WHERE yy = yyyy; +yy c2 yyyy c4 +70 1970 1970 1970 +99 1999 1999 1999 +00 2000 2000 2000 +01 2001 2001 2001 +69 2069 2069 2069 +SELECT * FROM t2, t4 WHERE yy <=> yyyy; +yy c2 yyyy c4 +NULL NULL NULL NULL +70 1970 1970 1970 +99 1999 1999 1999 +00 2000 2000 2000 +01 2001 2001 2001 +69 2069 2069 2069 +SELECT * FROM t2, t4 WHERE yy < yyyy; +yy c2 yyyy c4 +70 1970 1999 1999 +70 1970 2000 2000 +99 1999 2000 2000 +70 1970 2001 2001 +99 1999 2001 2001 +00 2000 2001 2001 +70 1970 2069 2069 +99 1999 2069 2069 +00 2000 2069 2069 +01 2001 2069 2069 +SELECT * FROM t2, t4 WHERE yy > yyyy; +yy c2 yyyy c4 +99 1999 1970 1970 +00 2000 1970 1970 +01 2001 1970 1970 +69 2069 1970 1970 +00 2000 1999 1999 +01 2001 1999 1999 +69 2069 1999 1999 +01 2001 2000 2000 +69 2069 2000 2000 +69 2069 2001 2001 +# Comparison of YEAR(2) with YEAR(2) +SELECT * FROM t2 a, t2 b WHERE a.yy = b.yy; +yy c2 yy c2 +70 1970 70 1970 +99 1999 99 1999 +00 2000 00 2000 +01 2001 01 2001 +69 2069 69 2069 +SELECT * FROM t2 a, t2 b WHERE a.yy <=> b.yy; +yy c2 yy c2 +NULL NULL NULL NULL +70 1970 70 1970 +99 1999 99 1999 +00 2000 00 2000 +01 2001 01 2001 +69 2069 69 2069 +SELECT * FROM t2 a, t2 b WHERE a.yy < b.yy; +yy c2 yy c2 +70 1970 99 1999 +70 1970 00 2000 +99 1999 00 2000 +70 1970 01 2001 +99 1999 01 2001 +00 2000 01 2001 +70 1970 69 2069 +99 1999 69 2069 +00 2000 69 2069 +01 2001 69 2069 +# Comparison of YEAR(4) with YEAR(4) +SELECT * FROM t4 a, t4 b WHERE a.yyyy = b.yyyy; +yyyy c4 yyyy c4 +1970 1970 1970 1970 +1999 1999 1999 1999 +2000 2000 2000 2000 +2001 2001 2001 2001 +2069 2069 2069 2069 +SELECT * FROM t4 a, t4 b WHERE a.yyyy <=> b.yyyy; +yyyy c4 yyyy c4 +NULL NULL NULL NULL +1970 1970 1970 1970 +1999 1999 1999 1999 +2000 2000 2000 2000 +2001 2001 2001 2001 +2069 2069 2069 2069 +SELECT * FROM t4 a, t4 b WHERE a.yyyy < b.yyyy; +yyyy c4 yyyy c4 +1970 1970 1999 1999 +1970 1970 2000 2000 +1999 1999 2000 2000 +1970 1970 2001 2001 +1999 1999 2001 2001 +2000 2000 2001 2001 +1970 1970 2069 2069 +1999 1999 2069 2069 +2000 2000 2069 2069 +2001 2001 2069 2069 +# Comparison with constants: +SELECT * FROM t2 WHERE yy = NULL; +yy c2 +SELECT * FROM t4 WHERE yyyy = NULL; +yyyy c4 +SELECT * FROM t2 WHERE yy <=> NULL; +yy c2 +NULL NULL +SELECT * FROM t4 WHERE yyyy <=> NULL; +yyyy c4 +NULL NULL +SELECT * FROM t2 WHERE yy < NULL; +yy c2 +SELECT * FROM t2 WHERE yy > NULL; +yy c2 +SELECT * FROM t2 WHERE yy = NOW(); +yy c2 +SELECT * FROM t4 WHERE yyyy = NOW(); +yyyy c4 +SELECT * FROM t2 WHERE yy = 99; +yy c2 +99 1999 +SELECT * FROM t2 WHERE 99 = yy; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 99; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 'test'; +yy c2 +00 2000 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'test' +SELECT * FROM t4 WHERE yyyy = 'test'; +yyyy c4 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'test' +SELECT * FROM t2 WHERE yy = '1999'; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = '1999'; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 1999; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 1999; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 1999.1; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 1999.1; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 1998.9; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 1998.9; +yyyy c4 +1999 1999 +# Coverage tests for YEAR with zero/2000 constants: +SELECT * FROM t2 WHERE yy = 0; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = '0'; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = '0000'; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = '2000'; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = 2000; +yy c2 +00 2000 +SELECT * FROM t4 WHERE yyyy = 0; +yyyy c4 +SELECT * FROM t4 WHERE yyyy = '0'; +yyyy c4 +2000 2000 +SELECT * FROM t4 WHERE yyyy = '0000'; +yyyy c4 +SELECT * FROM t4 WHERE yyyy = '2000'; +yyyy c4 +2000 2000 +SELECT * FROM t4 WHERE yyyy = 2000; +yyyy c4 +2000 2000 +# Comparison with constants those are out of YEAR range +# (coverage test for backward compatibility) +SELECT COUNT(yy) FROM t2; +COUNT(yy) +5 +SELECT COUNT(yyyy) FROM t4; +COUNT(yyyy) +5 +SELECT COUNT(*) FROM t2 WHERE yy = -1; +COUNT(*) +0 +SELECT COUNT(*) FROM t4 WHERE yyyy > -1; +COUNT(*) +5 +SELECT COUNT(*) FROM t2 WHERE yy > -1000000000000000000; +COUNT(*) +5 +SELECT COUNT(*) FROM t4 WHERE yyyy > -1000000000000000000; +COUNT(*) +5 +SELECT COUNT(*) FROM t2 WHERE yy < 2156; +COUNT(*) +5 +SELECT COUNT(*) FROM t4 WHERE yyyy < 2156; +COUNT(*) +5 +SELECT COUNT(*) FROM t2 WHERE yy < 1000000000000000000; +COUNT(*) +5 +SELECT COUNT(*) FROM t4 WHERE yyyy < 1000000000000000000; +COUNT(*) +5 +SELECT * FROM t2 WHERE yy < 123; +yy c2 +70 1970 +99 1999 +00 2000 +01 2001 +69 2069 +SELECT * FROM t2 WHERE yy > 123; +yy c2 +SELECT * FROM t4 WHERE yyyy < 123; +yyyy c4 +SELECT * FROM t4 WHERE yyyy > 123; +yyyy c4 +1970 1970 +1999 1999 +2000 2000 +2001 2001 +2069 2069 +DROP TABLE t2, t4; +# +End of 5.1 tests diff --git a/mysql-test/t/type_year.test b/mysql-test/t/type_year.test index 0e174a556d6..16fd39a59d8 100644 --- a/mysql-test/t/type_year.test +++ b/mysql-test/t/type_year.test @@ -30,3 +30,109 @@ select * from t1; drop table t1; --echo End of 5.0 tests + +--echo # +--echo # Bug #49480: WHERE using YEAR columns returns unexpected results +--echo # + +CREATE TABLE t2(yy YEAR(2), c2 CHAR(4)); +CREATE TABLE t4(yyyy YEAR(4), c4 CHAR(4)); + +INSERT INTO t2 (c2) VALUES (NULL),(1970),(1999),(2000),(2001),(2069); +INSERT INTO t4 (c4) SELECT c2 FROM t2; +UPDATE t2 SET yy = c2; +UPDATE t4 SET yyyy = c4; + +SELECT * FROM t2; +SELECT * FROM t4; + +--echo # Comparison of YEAR(2) with YEAR(4) + +SELECT * FROM t2, t4 WHERE yy = yyyy; +SELECT * FROM t2, t4 WHERE yy <=> yyyy; +SELECT * FROM t2, t4 WHERE yy < yyyy; +SELECT * FROM t2, t4 WHERE yy > yyyy; + +--echo # Comparison of YEAR(2) with YEAR(2) + +SELECT * FROM t2 a, t2 b WHERE a.yy = b.yy; +SELECT * FROM t2 a, t2 b WHERE a.yy <=> b.yy; +SELECT * FROM t2 a, t2 b WHERE a.yy < b.yy; + +--echo # Comparison of YEAR(4) with YEAR(4) + +SELECT * FROM t4 a, t4 b WHERE a.yyyy = b.yyyy; +SELECT * FROM t4 a, t4 b WHERE a.yyyy <=> b.yyyy; +SELECT * FROM t4 a, t4 b WHERE a.yyyy < b.yyyy; + +--echo # Comparison with constants: + +SELECT * FROM t2 WHERE yy = NULL; +SELECT * FROM t4 WHERE yyyy = NULL; +SELECT * FROM t2 WHERE yy <=> NULL; +SELECT * FROM t4 WHERE yyyy <=> NULL; +SELECT * FROM t2 WHERE yy < NULL; +SELECT * FROM t2 WHERE yy > NULL; + +SELECT * FROM t2 WHERE yy = NOW(); +SELECT * FROM t4 WHERE yyyy = NOW(); + +SELECT * FROM t2 WHERE yy = 99; +SELECT * FROM t2 WHERE 99 = yy; +SELECT * FROM t4 WHERE yyyy = 99; + +SELECT * FROM t2 WHERE yy = 'test'; +SELECT * FROM t4 WHERE yyyy = 'test'; + +SELECT * FROM t2 WHERE yy = '1999'; +SELECT * FROM t4 WHERE yyyy = '1999'; + +SELECT * FROM t2 WHERE yy = 1999; +SELECT * FROM t4 WHERE yyyy = 1999; + +SELECT * FROM t2 WHERE yy = 1999.1; +SELECT * FROM t4 WHERE yyyy = 1999.1; + +SELECT * FROM t2 WHERE yy = 1998.9; +SELECT * FROM t4 WHERE yyyy = 1998.9; + +--echo # Coverage tests for YEAR with zero/2000 constants: + +SELECT * FROM t2 WHERE yy = 0; +SELECT * FROM t2 WHERE yy = '0'; +SELECT * FROM t2 WHERE yy = '0000'; +SELECT * FROM t2 WHERE yy = '2000'; +SELECT * FROM t2 WHERE yy = 2000; + +SELECT * FROM t4 WHERE yyyy = 0; +SELECT * FROM t4 WHERE yyyy = '0'; +SELECT * FROM t4 WHERE yyyy = '0000'; +SELECT * FROM t4 WHERE yyyy = '2000'; +SELECT * FROM t4 WHERE yyyy = 2000; + +--echo # Comparison with constants those are out of YEAR range +--echo # (coverage test for backward compatibility) + +SELECT COUNT(yy) FROM t2; +SELECT COUNT(yyyy) FROM t4; + +SELECT COUNT(*) FROM t2 WHERE yy = -1; +SELECT COUNT(*) FROM t4 WHERE yyyy > -1; +SELECT COUNT(*) FROM t2 WHERE yy > -1000000000000000000; +SELECT COUNT(*) FROM t4 WHERE yyyy > -1000000000000000000; + +SELECT COUNT(*) FROM t2 WHERE yy < 2156; +SELECT COUNT(*) FROM t4 WHERE yyyy < 2156; +SELECT COUNT(*) FROM t2 WHERE yy < 1000000000000000000; +SELECT COUNT(*) FROM t4 WHERE yyyy < 1000000000000000000; + +SELECT * FROM t2 WHERE yy < 123; +SELECT * FROM t2 WHERE yy > 123; +SELECT * FROM t4 WHERE yyyy < 123; +SELECT * FROM t4 WHERE yyyy > 123; + +DROP TABLE t2, t4; + +--echo # + +--echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fd5eca8911a..d99748b87a0 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -956,40 +956,9 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, if (agg_item_set_converter(coll, owner->func_name(), b, 1, MY_COLL_CMP_CONV, 1)) return 1; - } else if (type != ROW_RESULT && ((*a)->field_type() == MYSQL_TYPE_YEAR || - (*b)->field_type() == MYSQL_TYPE_YEAR)) - { - is_nulls_eq= is_owner_equal_func(); - year_as_datetime= FALSE; - - if ((*a)->is_datetime()) - { - year_as_datetime= TRUE; - get_value_a_func= &get_datetime_value; - } else if ((*a)->field_type() == MYSQL_TYPE_YEAR) - get_value_a_func= &get_year_value; - else - { - /* - Because convert_constant_item is called only for EXECUTE in PS mode - the value of get_value_x_func set in PREPARE might be not - valid for EXECUTE. - */ - get_value_a_func= NULL; - } - - if ((*b)->is_datetime()) - { - year_as_datetime= TRUE; - get_value_b_func= &get_datetime_value; - } else if ((*b)->field_type() == MYSQL_TYPE_YEAR) - get_value_b_func= &get_year_value; - else - get_value_b_func= NULL; - - func= &Arg_comparator::compare_year; - return 0; } + else if (try_year_cmp_func(type)) + return 0; a= cache_converted_constant(thd, a, &a_cache, type); b= cache_converted_constant(thd, b, &b_cache, type); @@ -997,6 +966,45 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, } +/* + Helper function to call from Arg_comparator::set_cmp_func() +*/ + +bool Arg_comparator::try_year_cmp_func(Item_result type) +{ + if (type == ROW_RESULT) + return FALSE; + + bool a_is_year= (*a)->field_type() == MYSQL_TYPE_YEAR; + bool b_is_year= (*b)->field_type() == MYSQL_TYPE_YEAR; + + if (!a_is_year && !b_is_year) + return FALSE; + + if (a_is_year && b_is_year) + { + get_value_a_func= &get_year_value; + get_value_b_func= &get_year_value; + } + else if (a_is_year && (*b)->is_datetime()) + { + get_value_a_func= &get_year_value; + get_value_b_func= &get_datetime_value; + } + else if (b_is_year && (*a)->is_datetime()) + { + get_value_b_func= &get_year_value; + get_value_a_func= &get_datetime_value; + } + else + return FALSE; + + is_nulls_eq= is_owner_equal_func(); + func= &Arg_comparator::compare_datetime; + + return TRUE; +} + /** Convert and cache a constant. @@ -1147,7 +1155,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, /* - Retrieves YEAR value of 19XX form from given item. + Retrieves YEAR value of 19XX-00-00 00:00:00 form from given item. SYNOPSIS get_year_value() @@ -1159,7 +1167,9 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, DESCRIPTION Retrieves the YEAR value of 19XX form from given item for comparison by the - compare_year() function. + compare_datetime() function. + Converts year to DATETIME of form YYYY-00-00 00:00:00 for the compatibility + with the get_datetime_value function result. RETURN obtained value @@ -1186,6 +1196,9 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, if (value <= 1900) value+= 1900; + /* Convert year to DATETIME of form YYYY-00-00 00:00:00 (YYYY0000000000). */ + value*= 10000000000LL; + return value; } @@ -1615,67 +1628,6 @@ int Arg_comparator::compare_e_row() } -/** - Compare values as YEAR. - - @details - Compare items as YEAR for EQUAL_FUNC and for other comparison functions. - The YEAR values of form 19XX are obtained with help of the get_year_value() - function. - If one of arguments is of DATE/DATETIME type its value is obtained - with help of the get_datetime_value function. In this case YEAR values - prior to comparison are converted to the ulonglong YYYY-00-00 00:00:00 - DATETIME form. - If an argument type neither YEAR nor DATE/DATEIME then val_int function - is used to obtain value for comparison. - - RETURN - If is_nulls_eq is TRUE: - 1 if items are equal or both are null - 0 otherwise - If is_nulls_eq is FALSE: - -1 a < b - 0 a == b or at least one of items is null - 1 a > b - See the table: - is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | - a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | - b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | - result | 1 | 0 | 0 |0/1| 0 | 0 | 0 |-1/0/1| -*/ - -int Arg_comparator::compare_year() -{ - bool a_is_null, b_is_null; - ulonglong val1= get_value_a_func ? - (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null) : - (*a)->val_int(); - ulonglong val2= get_value_b_func ? - (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null) : - (*b)->val_int(); - if (!(*a)->null_value) - { - if (!(*b)->null_value) - { - if (set_null) - owner->null_value= 0; - /* Convert year to DATETIME of form YYYY-00-00 00:00:00 when necessary. */ - if((*a)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) - val1*= 10000000000LL; - if((*b)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) - val2*= 10000000000LL; - - if (val1 < val2) return is_nulls_eq ? 0 : -1; - if (val1 == val2) return is_nulls_eq ? 1 : 0; - return is_nulls_eq ? 0 : 1; - } - } - if (set_null) - owner->null_value= is_nulls_eq ? 0 : 1; - return (is_nulls_eq && (*a)->null_value == (*b)->null_value) ? 1 : 0; -} - - void Item_func_truth::fix_length_and_dec() { maybe_null= 0; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 52af6a31c0c..d4542dac820 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -42,24 +42,22 @@ class Arg_comparator: public Sql_alloc bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC bool set_null; // TRUE <=> set owner->null_value // when one of arguments is NULL. - bool year_as_datetime; // TRUE <=> convert YEAR value to - // the YYYY-00-00 00:00:00 DATETIME - // format. See compare_year. enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE, CMP_DATE_WITH_STR, CMP_STR_WITH_DATE }; longlong (*get_value_a_func)(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); longlong (*get_value_b_func)(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); + bool try_year_cmp_func(Item_result type); public: DTCollation cmp_collation; /* Allow owner function to use string buffers. */ String value1, value2; Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0), - year_as_datetime(0), get_value_a_func(0), get_value_b_func(0) {}; + get_value_a_func(0), get_value_b_func(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), - a_cache(0), b_cache(0), set_null(0), year_as_datetime(0), + a_cache(0), b_cache(0), set_null(0), get_value_a_func(0), get_value_b_func(0) {}; int set_compare_func(Item_result_field *owner, Item_result type); @@ -101,7 +99,6 @@ public: int compare_real_fixed(); int compare_e_real_fixed(); int compare_datetime(); // compare args[0] & args[1] as DATETIMEs - int compare_year(); static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b, ulonglong *const_val_arg); From 7b7a5c6e7abb98e86f579332b35e35f78fd6f440 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 Dec 2009 10:54:53 +0200 Subject: [PATCH 27/35] Bug#49489: Uninitialized cache led to a wrong result. Merge the fix from 5.1-bugteam to 5.1-main --- mysql-test/r/select.result | 10 ++++++++++ mysql-test/t/select.test | 9 +++++++++ sql/item_cmpfunc.cc | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d0b2a575a32..1750051289a 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4609,4 +4609,14 @@ HAVING v <= 't' ORDER BY pk; v DROP TABLE t1; +# +# Bug#49489 Uninitialized cache led to a wrong result. +# +CREATE TABLE t1(c1 DOUBLE(5,4)); +INSERT INTO t1 VALUES (9.1234); +SELECT * FROM t1 WHERE c1 < 9.12345; +c1 +9.1234 +DROP TABLE t1; +# End of test for bug#49489. End of 5.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index ac65e5cbaf5..982aec726f7 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3964,4 +3964,13 @@ ORDER BY pk; DROP TABLE t1; +--echo # +--echo # Bug#49489 Uninitialized cache led to a wrong result. +--echo # +CREATE TABLE t1(c1 DOUBLE(5,4)); +INSERT INTO t1 VALUES (9.1234); +SELECT * FROM t1 WHERE c1 < 9.12345; +DROP TABLE t1; +--echo # End of test for bug#49489. + --echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d99748b87a0..419b79377d7 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1031,7 +1031,7 @@ Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value, (*value)->const_item() && type != (*value)->result_type()) { Item_cache *cache= Item_cache::get_cache(*value, type); - cache->store(*value); + cache->setup(*value); *cache_item= cache; return cache_item; } From b4def7bea14b2102166365c44e359a26ae92d39b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 Dec 2009 11:03:24 +0200 Subject: [PATCH 28/35] Bug #48985: show create table crashes if previous access to the table was killed Merge the fix from 5.1-bugteam to 5.1-main --- mysql-test/r/show_check.result | 6 ++++++ mysql-test/t/show_check.test | 22 ++++++++++++++++++++++ sql/sql_show.cc | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index e6550bee954..ec0a70ff581 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -1454,4 +1454,10 @@ GRANT PROCESS ON *.* TO test_u@localhost; SHOW ENGINE MYISAM MUTEX; SHOW ENGINE MYISAM STATUS; DROP USER test_u@localhost; +# +# Bug #48985: show create table crashes if previous access to the table +# was killed +# +SHOW CREATE TABLE non_existent; +ERROR 70100: Query execution was interrupted End of 5.1 tests diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index 0ce807ae73e..d46261f38d2 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -1207,6 +1207,28 @@ connection default; DROP USER test_u@localhost; +--echo # +--echo # Bug #48985: show create table crashes if previous access to the table +--echo # was killed +--echo # + +connect(con1,localhost,root,,); +CONNECTION con1; +LET $ID= `SELECT connection_id()`; + +CONNECTION default; +--disable_query_log +eval KILL QUERY $ID; +--enable_query_log + +CONNECTION con1; +--error ER_QUERY_INTERRUPTED +SHOW CREATE TABLE non_existent; + +CONNECTION default; +DISCONNECT con1; + + --echo End of 5.1 tests # Wait till all disconnects are completed diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2c1f360104b..e55000c0f65 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -719,7 +719,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) thd->push_internal_handler(&view_error_suppressor); bool error= open_normal_and_derived_tables(thd, table_list, 0); thd->pop_internal_handler(); - if (error && thd->main_da.is_error()) + if (error && (thd->killed || thd->main_da.is_error())) DBUG_RETURN(TRUE); } From 4422b0f665fa3cba9f86b1c5e8e242f7839f6335 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Tue, 15 Dec 2009 21:08:21 +0400 Subject: [PATCH 29/35] Fix for bug#49517: Inconsistent behavior while using NULLable BIGINT and INT columns in comparison Problem: a consequence of the fix for 43668. Some Arg_comparator inner initialization missed, that may lead to unpredictable (wrong) comparison results. Fix: always properly initialize Arg_comparator before its usage. --- mysql-test/r/select.result | 15 +++++++++++++++ mysql-test/t/select.test | 14 ++++++++++++++ sql/item_cmpfunc.cc | 2 +- sql/item_cmpfunc.h | 4 ++-- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 1750051289a..f38af4ceb32 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4619,4 +4619,19 @@ c1 9.1234 DROP TABLE t1; # End of test for bug#49489. +# +# Bug #49517: Inconsistent behavior while using +# NULLable BIGINT and INT columns in comparison +# +CREATE TABLE t1(a BIGINT UNSIGNED NOT NULL, b BIGINT NULL, c INT NULL); +INSERT INTO t1 VALUES(105, NULL, NULL); +SELECT * FROM t1 WHERE b < 102; +a b c +SELECT * FROM t1 WHERE c < 102; +a b c +SELECT * FROM t1 WHERE 102 < b; +a b c +SELECT * FROM t1 WHERE 102 < c; +a b c +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 982aec726f7..e81c298166d 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3973,4 +3973,18 @@ SELECT * FROM t1 WHERE c1 < 9.12345; DROP TABLE t1; --echo # End of test for bug#49489. + +--echo # +--echo # Bug #49517: Inconsistent behavior while using +--echo # NULLable BIGINT and INT columns in comparison +--echo # +CREATE TABLE t1(a BIGINT UNSIGNED NOT NULL, b BIGINT NULL, c INT NULL); +INSERT INTO t1 VALUES(105, NULL, NULL); +SELECT * FROM t1 WHERE b < 102; +SELECT * FROM t1 WHERE c < 102; +SELECT * FROM t1 WHERE 102 < b; +SELECT * FROM t1 WHERE 102 < c; +DROP TABLE t1; + + --echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 419b79377d7..e4f26978431 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -895,9 +895,9 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, ulonglong const_value= (ulonglong)-1; thd= current_thd; owner= owner_arg; + set_null= set_null && owner_arg; a= a1; b= a2; - owner= owner_arg; thd= current_thd; if ((cmp_type= can_compare_as_dates(*a, *b, &const_value))) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index d4542dac820..05c9fc96ff5 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -54,10 +54,10 @@ public: /* Allow owner function to use string buffers. */ String value1, value2; - Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0), + Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(TRUE), get_value_a_func(0), get_value_b_func(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), - a_cache(0), b_cache(0), set_null(0), + a_cache(0), b_cache(0), set_null(TRUE), get_value_a_func(0), get_value_b_func(0) {}; int set_compare_func(Item_result_field *owner, Item_result type); From d64f0493511b161b2b18c0fea82ffb0c14e16a91 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Wed, 30 Dec 2009 23:06:14 +0100 Subject: [PATCH 30/35] Removed unwanted Perl DBI dependency --- support-files/mysql.spec.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 8209c4560c6..b6d822d8719 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -65,6 +65,19 @@ # See BUG#998 for details. %define _unpackaged_files_terminate_build 0 +# ------------------------------------------------------------------------------ +# RPM build tools now automatically detects Perl module dependencies. This +# detection gives problems as it is broken in some versions, and it also +# give unwanted dependencies from mandatory scripts in our package. +# Might not be possible to disable in all RPM tool versions, but here we +# try. We keep the "AutoReqProv: no" for the "test" sub package, as disabling +# here might fail, and that package has the most problems. +# See http://fedoraproject.org/wiki/Packaging/Perl#Filtering_Requires:_and_Provides +# http://www.wideopen.com/archives/rpm-list/2002-October/msg00343.html +# ------------------------------------------------------------------------------ +%undefine __perl_provides +%undefine __perl_requires + %define see_base For a description of MySQL see the base MySQL RPM or http://www.mysql.com # On SuSE 9 no separate "debuginfo" package is built. To enable basic @@ -205,7 +218,7 @@ They should be used with caution. %endif %package test -Requires: %{name}-client perl-DBI perl +Requires: %{name}-client perl Summary: MySQL - Test suite Group: Applications/Databases Provides: mysql-test From 789352e87b11ed3ac9599a5b2b1311d99965c376 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Tue, 12 Jan 2010 12:41:18 +0100 Subject: [PATCH 31/35] Implement the change of RPM versioning and file naming: - "release" starts from 1 - "level" ("m2", "rc", ...) is included in the RPM version. --- configure.in | 13 ++++++++----- support-files/Makefile.am | 3 ++- support-files/mysql.spec.sh | 14 ++++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/configure.in b/configure.in index b206dfbd079..405ebddadbe 100644 --- a/configure.in +++ b/configure.in @@ -30,12 +30,14 @@ NDB_VERSION_STATUS="" # Remember that regexps needs to quote [ and ] since this is run through m4 # We take some made up examples # -# VERSION 5.1.40sp1-alpha 5.0.34a -# MYSQL_NO_DASH_VERSION 5.1.40sp1 5.0.34a -# MYSQL_NUMERIC_VERSION 5.1.40 5.0.34 -# MYSQL_BASE_VERSION 5.1 5.0 -# MYSQL_VERSION_ID 50140 50034 +# VERSION 5.1.40sp1-alpha 5.0.34a 5.5.1-m2 +# MYSQL_U_SCORE_VERSION 5.1.40sp1_alpha 5.0.34a 5.5.1_m2 +# MYSQL_NO_DASH_VERSION 5.1.40sp1 5.0.34a 5.5.1 +# MYSQL_NUMERIC_VERSION 5.1.40 5.0.34 5.5.1 +# MYSQL_BASE_VERSION 5.1 5.0 5.5 +# MYSQL_VERSION_ID 50140 50034 50501 # +MYSQL_U_SCORE_VERSION=`echo $VERSION | sed -e "s|-|_|"` MYSQL_NO_DASH_VERSION=`echo $VERSION | sed -e "s|-.*$||"` MYSQL_NUMERIC_VERSION=`echo $MYSQL_NO_DASH_VERSION | sed -e "s|[[a-z]][[a-z0-9]]*$||"` MYSQL_BASE_VERSION=`echo $MYSQL_NUMERIC_VERSION | sed -e "s|\.[[^.]]*$||"` @@ -78,6 +80,7 @@ romanian russian serbian slovak spanish swedish ukrainian" ##### ##### +AC_SUBST(MYSQL_U_SCORE_VERSION) AC_SUBST(MYSQL_NO_DASH_VERSION) AC_SUBST(MYSQL_BASE_VERSION) AC_SUBST(MYSQL_VERSION_ID) diff --git a/support-files/Makefile.am b/support-files/Makefile.am index b9d6fde742a..4cb8bb4645d 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2000-2001, 2003-2006 MySQL AB +# Copyright (C) 2000-2006 MySQL AB, 2008-2010 Sun Microsystems, Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public @@ -104,6 +104,7 @@ SUFFIXES = .sh -e 's!@''SHARED_LIB_VERSION''@!@SHARED_LIB_VERSION@!' \ -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \ -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \ + -e 's!@''MYSQL_U_SCORE_VERSION''@!@MYSQL_U_SCORE_VERSION@!' \ -e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \ -e 's!@''PERL_DBI_VERSION''@!@PERL_DBI_VERSION@!' \ -e 's!@''PERL_DBD_VERSION''@!@PERL_DBD_VERSION@!' \ diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 584c0abc777..98f715da94d 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1,4 +1,4 @@ -# Copyright (C) 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +# Copyright (C) 2000-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -28,9 +28,9 @@ %{!?_with_yassl:%define YASSL_BUILD 0} %if %{STATIC_BUILD} -%define release 0 +%define release 1 %else -%define release 0.glibc23 +%define release 1.glibc23 %endif %define license GPL %define mysqld_user mysql @@ -64,7 +64,7 @@ Name: MySQL Summary: MySQL: a very fast and reliable SQL database server Group: Applications/Databases -Version: @MYSQL_NO_DASH_VERSION@ +Version: @MYSQL_U_SCORE_VERSION@ Release: %{release} License: %{license} Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/mysql-%{mysql_version}.tar.gz @@ -818,6 +818,12 @@ fi # itself - note that they must be ordered by date (important when # merging BK trees) %changelog +* Mon Jan 11 2010 Joerg Bruehe + +- Change RPM file naming: + - Suffix like "-m2", "-rc" becomes part of version as "_m2", "_rc". + - Release counts from 1, not 0. + * Fri Nov 07 2008 Joerg Bruehe - Correct yesterday's fix, so that it also works for the last flag. From 30212033ede6f95a860a3a7a22c3e73f580e17b9 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Wed, 13 Jan 2010 08:16:36 +0400 Subject: [PATCH 32/35] Bug #50096: CONCAT_WS inside procedure returning wrong data Selecting of the CONCAT_WS(......) result into a user variable may return wrong data. Item_func_concat_ws::val_str contains a number of memory allocation-saving optimization tricks. After the fix for bug 46815 the control flow has been changed to a branch that is commented as "This is quite uncommon!": one of places where we are trying to concatenate strings inplace. However, that "uncommon" place didn't care about PS parameters, that have another trick in Item_sp_variable::val_str(): they use the intermediate Item_sp_variable::str_value field, where they may store a reference to an external argument's buffer. The Item_func_concat_ws::val_str function has been modified to take into account val_str functions (such as Item_sp_variable::val_str) that return a pointer to an internal Item member variable that may reference to a buffer provided. --- mysql-test/r/func_concat.result | 11 +++++++++++ mysql-test/t/func_concat.test | 13 +++++++++++++ sql/item_strfunc.cc | 4 ++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_concat.result b/mysql-test/r/func_concat.result index 75b4888fbb2..c4c2b46c6c2 100644 --- a/mysql-test/r/func_concat.result +++ b/mysql-test/r/func_concat.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; CREATE TABLE t1 ( number INT NOT NULL, alpha CHAR(6) NOT NULL ); INSERT INTO t1 VALUES (1413006,'idlfmv'), (1413065,'smpsfz'),(1413127,'sljrhx'),(1413304,'qerfnd'); @@ -119,4 +120,14 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index NULL PRIMARY 102 NULL 3 Using index 1 SIMPLE t1 eq_ref PRIMARY,a PRIMARY 318 func,const,const 1 DROP TABLE t1, t2; +# +# Bug #50096: CONCAT_WS inside procedure returning wrong data +# +CREATE PROCEDURE p1(a varchar(255), b int, c int) +SET @query = CONCAT_WS(",", a, b, c); +CALL p1("abcde", "0", "1234"); +SELECT @query; +@query +abcde,0,1234 +DROP PROCEDURE p1; # End of 5.1 tests diff --git a/mysql-test/t/func_concat.test b/mysql-test/t/func_concat.test index 1c7e5823fb2..e24b4354b61 100644 --- a/mysql-test/t/func_concat.test +++ b/mysql-test/t/func_concat.test @@ -4,6 +4,7 @@ --disable_warnings DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; --enable_warnings CREATE TABLE t1 ( number INT NOT NULL, alpha CHAR(6) NOT NULL ); @@ -111,4 +112,16 @@ EXPLAIN SELECT CONCAT('gui_', t2.a), t1.d FROM t2 DROP TABLE t1, t2; +--echo # +--echo # Bug #50096: CONCAT_WS inside procedure returning wrong data +--echo # + +CREATE PROCEDURE p1(a varchar(255), b int, c int) + SET @query = CONCAT_WS(",", a, b, c); + +CALL p1("abcde", "0", "1234"); +SELECT @query; + +DROP PROCEDURE p1; + --echo # End of 5.1 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b6d3f45f4c2..ecd839d8378 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -677,8 +677,8 @@ String *Item_func_concat_ws::val_str(String *str) res->length() + sep_str->length() + res2->length()) { /* We have room in str; We can't get any errors here */ - if (str == res2) - { // This is quote uncommon! + if (str->ptr() == res2->ptr()) + { // This is quite uncommon! str->replace(0,0,*sep_str); str->replace(0,0,*res); } From 5622b586d980ec9aa9fd1f3eb73e8c97135e1269 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Wed, 13 Jan 2010 09:20:45 +0400 Subject: [PATCH 33/35] Fix for bug#50227: Pre-auth buffer-overflow in mySQL through yaSSL Problem: copying issuer's (or subject's) name tags into an internal buffer from incoming stream we didn't check the buffer overflow. That may lead to memory overrun, crash etc. Fix: ensure we don't overrun the buffer. Note: there's no simple test case (exploit needed). --- extra/yassl/taocrypt/include/asn.hpp | 1 + extra/yassl/taocrypt/src/asn.cpp | 123 +++++++++++++++------------ 2 files changed, 69 insertions(+), 55 deletions(-) diff --git a/extra/yassl/taocrypt/include/asn.hpp b/extra/yassl/taocrypt/include/asn.hpp index 1c1850cb47e..168b8a8c755 100644 --- a/extra/yassl/taocrypt/include/asn.hpp +++ b/extra/yassl/taocrypt/include/asn.hpp @@ -305,6 +305,7 @@ private: bool ValidateSignature(SignerList*); bool ConfirmSignature(Source&); void GetKey(); + char* AddTag(char*, const char*, const char*, word32, word32); void GetName(NameType); void GetValidity(); void GetDate(DateType); diff --git a/extra/yassl/taocrypt/src/asn.cpp b/extra/yassl/taocrypt/src/asn.cpp index 78200841bda..f87b466502e 100644 --- a/extra/yassl/taocrypt/src/asn.cpp +++ b/extra/yassl/taocrypt/src/asn.cpp @@ -652,6 +652,23 @@ word32 CertDecoder::GetDigest() } +char *CertDecoder::AddTag(char *ptr, const char *buf_end, + const char *tag_name, word32 tag_name_length, + word32 tag_value_length) +{ + if (ptr + tag_name_length + tag_value_length > buf_end) + return 0; + + memcpy(ptr, tag_name, tag_name_length); + ptr+= tag_name_length; + + memcpy(ptr, source_.get_current(), tag_value_length); + ptr+= tag_value_length; + + return ptr; +} + + // process NAME, either issuer or subject void CertDecoder::GetName(NameType nt) { @@ -659,11 +676,21 @@ void CertDecoder::GetName(NameType nt) SHA sha; word32 length = GetSequence(); // length of all distinguished names - assert (length < ASN_NAME_MAX); + + if (length >= ASN_NAME_MAX) + goto err; length += source_.get_index(); - char* ptr = (nt == ISSUER) ? issuer_ : subject_; - word32 idx = 0; + char *ptr, *buf_end; + + if (nt == ISSUER) { + ptr= issuer_; + buf_end= ptr + sizeof(issuer_) - 1; // 1 byte for trailing 0 + } + else { + ptr= subject_; + buf_end= ptr + sizeof(subject_) - 1; // 1 byte for trailing 0 + } while (source_.get_index() < length) { GetSet(); @@ -685,47 +712,36 @@ void CertDecoder::GetName(NameType nt) byte id = source_.next(); b = source_.next(); // strType word32 strLen = GetLength(source_); - bool copy = false; - if (id == COMMON_NAME) { - memcpy(&ptr[idx], "/CN=", 4); - idx += 4; - copy = true; - } - else if (id == SUR_NAME) { - memcpy(&ptr[idx], "/SN=", 4); - idx += 4; - copy = true; - } - else if (id == COUNTRY_NAME) { - memcpy(&ptr[idx], "/C=", 3); - idx += 3; - copy = true; - } - else if (id == LOCALITY_NAME) { - memcpy(&ptr[idx], "/L=", 3); - idx += 3; - copy = true; - } - else if (id == STATE_NAME) { - memcpy(&ptr[idx], "/ST=", 4); - idx += 4; - copy = true; - } - else if (id == ORG_NAME) { - memcpy(&ptr[idx], "/O=", 3); - idx += 3; - copy = true; - } - else if (id == ORGUNIT_NAME) { - memcpy(&ptr[idx], "/OU=", 4); - idx += 4; - copy = true; - } - - if (copy) { - memcpy(&ptr[idx], source_.get_current(), strLen); - idx += strLen; + switch (id) { + case COMMON_NAME: + if (!(ptr= AddTag(ptr, buf_end, "/CN=", 4, strLen))) + goto err; + break; + case SUR_NAME: + if (!(ptr= AddTag(ptr, buf_end, "/SN=", 4, strLen))) + goto err; + break; + case COUNTRY_NAME: + if (!(ptr= AddTag(ptr, buf_end, "/C=", 3, strLen))) + goto err; + break; + case LOCALITY_NAME: + if (!(ptr= AddTag(ptr, buf_end, "/L=", 3, strLen))) + goto err; + break; + case STATE_NAME: + if (!(ptr= AddTag(ptr, buf_end, "/ST=", 4, strLen))) + goto err; + break; + case ORG_NAME: + if (!(ptr= AddTag(ptr, buf_end, "/O=", 3, strLen))) + goto err; + break; + case ORGUNIT_NAME: + if (!(ptr= AddTag(ptr, buf_end, "/OU=", 4, strLen))) + goto err; + break; } sha.Update(source_.get_current(), strLen); @@ -739,23 +755,20 @@ void CertDecoder::GetName(NameType nt) source_.advance(oidSz + 1); word32 length = GetLength(source_); - if (email) { - memcpy(&ptr[idx], "/emailAddress=", 14); - idx += 14; - - memcpy(&ptr[idx], source_.get_current(), length); - idx += length; - } + if (email && !(ptr= AddTag(ptr, buf_end, "/emailAddress=", 14, length))) + goto err; source_.advance(length); } } - ptr[idx++] = 0; + *ptr= 0; - if (nt == ISSUER) - sha.Final(issuerHash_); - else - sha.Final(subjectHash_); + sha.Final(nt == ISSUER ? issuerHash_ : subjectHash_); + + return; + +err: + source_.SetError(CONTENT_E); } From 94946c680762954a5b88ea46b93e3975995cf504 Mon Sep 17 00:00:00 2001 From: Sven Sandberg Date: Wed, 13 Jan 2010 10:00:03 +0100 Subject: [PATCH 34/35] BUG#49222: Mark RAND() as unsafe Problem: When RAND() is binlogged in statement mode, the seed is binlogged too, so the replication slave generates the same sequence of random numbers. This makes replication work in many cases, but not in all cases: the order of rows is not guaranteed for, e.g., UPDATE or INSERT...SELECT statements, so the row data will be different if master and slave retrieve the rows in different orders. Fix: Mark RAND() as unsafe. It will generate a warning if binlog_format=STATEMENT and switch to row-logging if binlog_format=ROW. --- .../extra/rpl_tests/rpl_row_func003.test | 6 +++++ .../suite/binlog/r/binlog_unsafe.result | 3 +++ mysql-test/suite/binlog/t/binlog_unsafe.test | 24 +++++++++++-------- .../suite/rpl/r/rpl_misc_functions.result | 1 + .../r/rpl_nondeterministic_functions.result | 1 + mysql-test/suite/rpl/r/rpl_optimize.result | 1 + mysql-test/suite/rpl/r/rpl_row_func003.result | 1 + .../suite/rpl/t/rpl_misc_functions.test | 8 +++++++ .../rpl/t/rpl_nondeterministic_functions.test | 4 ++++ mysql-test/suite/rpl/t/rpl_optimize.test | 4 +++- mysql-test/suite/rpl/t/rpl_trigger.test | 2 ++ .../suite/rpl_ndb/r/rpl_ndb_func003.result | 1 + sql/item_create.cc | 10 ++++++++ 13 files changed, 55 insertions(+), 11 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_row_func003.test b/mysql-test/extra/rpl_tests/rpl_row_func003.test index 8ee2d863527..b77465de39e 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_func003.test +++ b/mysql-test/extra/rpl_tests/rpl_row_func003.test @@ -18,6 +18,8 @@ # Vs slave. # ############################################################################# +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); + # Begin clean up test section connection master; --disable_warnings @@ -43,10 +45,12 @@ RETURN tmp; END| delimiter ;| +--disable_warnings INSERT INTO test.t1 VALUES (null,test.f1()),(null,test.f1()),(null,test.f1()); sleep 6; INSERT INTO test.t1 VALUES (null,test.f1()),(null,test.f1()),(null,test.f1()); sleep 6; +--enable_warnings #Select in this test are used for debugging #select * from test.t1; @@ -56,7 +60,9 @@ sleep 6; connection master; SET AUTOCOMMIT=0; START TRANSACTION; +--disable_warnings INSERT INTO test.t1 VALUES (null,test.f1()); +--enable_warnings ROLLBACK; SET AUTOCOMMIT=1; #select * from test.t1; diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result index 8bbf993a727..6b2a83c9483 100644 --- a/mysql-test/suite/binlog/r/binlog_unsafe.result +++ b/mysql-test/suite/binlog/r/binlog_unsafe.result @@ -379,6 +379,9 @@ Note 1592 Statement may not be safe to log in statement format. INSERT INTO t1 VALUES (VERSION()); Warnings: Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (RAND()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. DELETE FROM t1; SET TIMESTAMP=1000000; INSERT INTO t1 VALUES diff --git a/mysql-test/suite/binlog/t/binlog_unsafe.test b/mysql-test/suite/binlog/t/binlog_unsafe.test index 1acb4d090ca..5e399f3e602 100644 --- a/mysql-test/suite/binlog/t/binlog_unsafe.test +++ b/mysql-test/suite/binlog/t/binlog_unsafe.test @@ -47,6 +47,8 @@ # BUG#34768: nondeterministic INSERT using LIMIT logged in stmt mode if binlog_format=mixed # BUG#41980, SBL, INSERT .. SELECT .. LIMIT = ERROR, even when @@SQL_LOG_BIN is 0 # BUG#42640: mysqld crashes when unsafe statements are executed (STRICT_TRANS_TABLES mode) +# BUG#47995: Mark user functions as unsafe +# BUG#49222: Mare RAND() unsafe # # ==== Related test cases ==== # @@ -391,6 +393,7 @@ SET @@SESSION.SQL_MODE = @save_sql_mode; # # BUG#47995: Mark user functions as unsafe +# BUG#49222: Mare RAND() unsafe # # Test that the system functions that are supposed to be marked unsafe # generate a warning. Each INSERT statement below should generate a @@ -400,27 +403,28 @@ SET @@SESSION.SQL_MODE = @save_sql_mode; CREATE TABLE t1 (a VARCHAR(1000)); INSERT INTO t1 VALUES (CURRENT_USER()); #marked unsafe before BUG#47995 INSERT INTO t1 VALUES (FOUND_ROWS()); #marked unsafe before BUG#47995 -INSERT INTO t1 VALUES (GET_LOCK('tmp', 1)); -INSERT INTO t1 VALUES (IS_FREE_LOCK('tmp')); -INSERT INTO t1 VALUES (IS_USED_LOCK('tmp')); -INSERT INTO t1 VALUES (LOAD_FILE('../../std_data/words2.dat')); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (GET_LOCK('tmp', 1)); #marked unsafe in BUG#47995 +INSERT INTO t1 VALUES (IS_FREE_LOCK('tmp')); #marked unsafe in BUG#47995 +INSERT INTO t1 VALUES (IS_USED_LOCK('tmp')); #marked unsafe in BUG#47995 +INSERT INTO t1 VALUES (LOAD_FILE('../../std_data/words2.dat')); #marked unsafe in BUG#39701 INSERT INTO t1 VALUES (MASTER_POS_WAIT('dummy arg', 4711, 1)); -INSERT INTO t1 VALUES (RELEASE_LOCK('tmp')); +INSERT INTO t1 VALUES (RELEASE_LOCK('tmp')); #marked unsafe in BUG#47995 INSERT INTO t1 VALUES (ROW_COUNT()); #marked unsafe before BUG#47995 INSERT INTO t1 VALUES (SESSION_USER()); #marked unsafe before BUG#47995 -INSERT INTO t1 VALUES (SLEEP(1)); -INSERT INTO t1 VALUES (SYSDATE()); +INSERT INTO t1 VALUES (SLEEP(1)); #marked unsafe in BUG#47995 +INSERT INTO t1 VALUES (SYSDATE()); #marked unsafe in BUG#47995 INSERT INTO t1 VALUES (SYSTEM_USER()); #marked unsafe before BUG#47995 INSERT INTO t1 VALUES (USER()); #marked unsafe before BUG#47995 INSERT INTO t1 VALUES (UUID()); #marked unsafe before BUG#47995 INSERT INTO t1 VALUES (UUID_SHORT()); #marked unsafe before BUG#47995 -INSERT INTO t1 VALUES (VERSION()); +INSERT INTO t1 VALUES (VERSION()); #marked unsafe in BUG#47995 +INSERT INTO t1 VALUES (RAND()); #marked unsafe in BUG#49222 DELETE FROM t1; # Since we replicate the TIMESTAMP variable, functions affected by the # TIMESTAMP variable are safe to replicate. So we check that the -# following following functions depend on the TIMESTAMP variable and -# don't generate a warning. +# following following functions that depend on the TIMESTAMP variable +# are not unsafe and don't generate a warning. SET TIMESTAMP=1000000; INSERT INTO t1 VALUES diff --git a/mysql-test/suite/rpl/r/rpl_misc_functions.result b/mysql-test/suite/rpl/r/rpl_misc_functions.result index 28b777822e4..6d69235927e 100644 --- a/mysql-test/suite/rpl/r/rpl_misc_functions.result +++ b/mysql-test/suite/rpl/r/rpl_misc_functions.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); create table t1(id int, i int, r1 int, r2 int, p varchar(100)); insert into t1 values(1, connection_id(), 0, 0, ""); insert into t1 values(2, 0, rand()*1000, rand()*1000, ""); diff --git a/mysql-test/suite/rpl/r/rpl_nondeterministic_functions.result b/mysql-test/suite/rpl/r/rpl_nondeterministic_functions.result index c4842a284cd..3b9b741e040 100644 --- a/mysql-test/suite/rpl/r/rpl_nondeterministic_functions.result +++ b/mysql-test/suite/rpl/r/rpl_nondeterministic_functions.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); CREATE TABLE t1 (a VARCHAR(1000)); INSERT INTO t1 VALUES (CONNECTION_ID()); INSERT INTO t1 VALUES (CONNECTION_ID()); diff --git a/mysql-test/suite/rpl/r/rpl_optimize.result b/mysql-test/suite/rpl/r/rpl_optimize.result index 79891169fbc..1ae94a3ca36 100644 --- a/mysql-test/suite/rpl/r/rpl_optimize.result +++ b/mysql-test/suite/rpl/r/rpl_optimize.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); create table t1 (a int not null auto_increment primary key, b int, key(b)); INSERT INTO t1 (a) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); INSERT INTO t1 (a) SELECT null FROM t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_func003.result b/mysql-test/suite/rpl/r/rpl_row_func003.result index a5fd46a2ce3..94d01b50ce5 100644 --- a/mysql-test/suite/rpl/r/rpl_row_func003.result +++ b/mysql-test/suite/rpl/r/rpl_row_func003.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); DROP FUNCTION IF EXISTS test.f1; DROP TABLE IF EXISTS test.t1; CREATE TABLE test.t1 (a INT NOT NULL AUTO_INCREMENT, c CHAR(16),PRIMARY KEY(a))ENGINE=INNODB; diff --git a/mysql-test/suite/rpl/t/rpl_misc_functions.test b/mysql-test/suite/rpl/t/rpl_misc_functions.test index d2e61d579e3..b84042160cd 100644 --- a/mysql-test/suite/rpl/t/rpl_misc_functions.test +++ b/mysql-test/suite/rpl/t/rpl_misc_functions.test @@ -3,12 +3,16 @@ # source include/master-slave.inc; +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); + create table t1(id int, i int, r1 int, r2 int, p varchar(100)); insert into t1 values(1, connection_id(), 0, 0, ""); # don't put rand and password in the same query, to see if they replicate # independently # Pure rand test +--disable_warnings insert into t1 values(2, 0, rand()*1000, rand()*1000, ""); +--enable_warnings # change the rand suite on the master (we do this because otherwise password() # benefits from the fact that the above rand() is well replicated : # it picks the same sequence element, which hides a possible bug in password() replication. @@ -19,7 +23,9 @@ set sql_log_bin=1; # Pure password test insert into t1 values(3, 0, 0, 0, password('does_this_work?')); # "altogether now" +--disable_warnings insert into t1 values(4, connection_id(), rand()*1000, rand()*1000, password('does_this_still_work?')); +--enable_warnings select * into outfile 'rpl_misc_functions.outfile' from t1; let $MYSQLD_DATADIR= `select @@datadir`; sync_slave_with_master; @@ -73,11 +79,13 @@ DELIMITER ;| # Exercise the functions and procedures then compare the results on # the master to those on the slave. +--disable_warnings CALL test_replication_sp1(); CALL test_replication_sp2(); INSERT INTO t1 (col_a) VALUES (test_replication_sf()); INSERT INTO t1 (col_a) VALUES (test_replication_sf()); INSERT INTO t1 (col_a) VALUES (test_replication_sf()); +--enable_warnings --sync_slave_with_master diff --git a/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test b/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test index a30eb3be374..9ff2e2d081e 100644 --- a/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test +++ b/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test @@ -17,6 +17,8 @@ --source include/master-slave.inc +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); + CREATE TABLE t1 (a VARCHAR(1000)); # We replicate the connection_id in the query_log_event @@ -41,7 +43,9 @@ INSERT INTO t1 VALUES (UTC_TIMESTAMP()); # We replicate the random seed in a rand_log_event +--disable_warnings INSERT INTO t1 VALUES (RAND()); +--enable_warnings # We replicate the last_insert_id in an intvar_log_event INSERT INTO t1 VALUES (LAST_INSERT_ID()); diff --git a/mysql-test/suite/rpl/t/rpl_optimize.test b/mysql-test/suite/rpl/t/rpl_optimize.test index f4582ba1167..87eb9dce818 100644 --- a/mysql-test/suite/rpl/t/rpl_optimize.test +++ b/mysql-test/suite/rpl/t/rpl_optimize.test @@ -13,6 +13,8 @@ -- source include/not_ndb_default.inc -- source include/master-slave.inc +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); + create table t1 (a int not null auto_increment primary key, b int, key(b)); INSERT INTO t1 (a) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); INSERT INTO t1 (a) SELECT null FROM t1; @@ -30,8 +32,8 @@ INSERT INTO t1 (a) SELECT null FROM t1; INSERT INTO t1 (a) SELECT null FROM t1; save_master_pos; # a few updates to force OPTIMIZE to do something -update t1 set b=(a/2*rand()); --disable_warnings +update t1 set b=(a/2*rand()); delete from t1 order by b limit 10000; --enable_warnings diff --git a/mysql-test/suite/rpl/t/rpl_trigger.test b/mysql-test/suite/rpl/t/rpl_trigger.test index 4b40fbea719..e296da01bad 100644 --- a/mysql-test/suite/rpl/t/rpl_trigger.test +++ b/mysql-test/suite/rpl/t/rpl_trigger.test @@ -40,10 +40,12 @@ insert into t3 values(100,"log",0,0,0); SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186; # Emulate that we have rows 2-9 deleted on the slave +--disable_warnings insert into t1 values(1,1,rand()),(NULL,2,rand()); insert into t2 (b) values(last_insert_id()); insert into t2 values(3,0),(NULL,0); insert into t2 values(NULL,0),(500,0); +--enable_warnings select a,b, truncate(rand_value,4) from t1; select * from t2; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_func003.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_func003.result index ad72a3fb244..7e750f2ce2a 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_func003.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_func003.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression('Statement may not be safe to log in statement format.'); DROP FUNCTION IF EXISTS test.f1; DROP TABLE IF EXISTS test.t1; CREATE TABLE test.t1 (a INT NOT NULL AUTO_INCREMENT, c CHAR(16),PRIMARY KEY(a))ENGINE=NDB; diff --git a/sql/item_create.cc b/sql/item_create.cc index 53aa8081da1..c309ccc06ca 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -4178,6 +4178,16 @@ Create_func_rand::create_native(THD *thd, LEX_STRING name, if (item_list != NULL) arg_count= item_list->elements; + /* + When RAND() is binlogged, the seed is binlogged too. So the + sequence of random numbers is the same on a replication slave as + on the master. However, if several RAND() values are inserted + into a table, the order in which the rows are modified may differ + between master and slave, because the order is undefined. Hence, + the statement is unsafe to log in statement format. + */ + thd->lex->set_stmt_unsafe(); + switch (arg_count) { case 0: { From b433f7f23ac8c27cb3ee9b9066e6fe445fc6382d Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 13 Jan 2010 12:43:07 +0200 Subject: [PATCH 35/35] version change --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index f044f8e62da..e613cefc614 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.1" +tree_name = "mysql-5.1-bugteam"