From c8693bea40c8d0d3f678e263c474ee82b193f62e Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 26 Sep 2013 23:48:38 +0200 Subject: [PATCH 1/9] MDEV-5076 : Build on FreeBSD - when looking for execinfo library, and execinfo.h header, allow user-defined EXECINFO_ROOT prefix, in case library and header are not placed under /usr/local . This change was requested by FreeBSD maintainer. --- cmake/os/FreeBSD.cmake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmake/os/FreeBSD.cmake b/cmake/os/FreeBSD.cmake index 3a5a29f6de6..ffb89c81206 100644 --- a/cmake/os/FreeBSD.cmake +++ b/cmake/os/FreeBSD.cmake @@ -24,9 +24,10 @@ # ADD_DEFINITIONS(-DHAVE_BROKEN_REALPATH) # Find libexecinfo (library that contains backtrace_symbols etc) -INCLUDE_DIRECTORIES(/usr/local/include) -SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} /usr/local/include ) -SET(ENV{LIB} "$ENV{LIB}:/usr/local/lib") +SET(EXECINFO_ROOT /usr/local CACHE INTERNAL "Where to find execinfo library and header") +INCLUDE_DIRECTORIES(${EXECINFO_ROOT}/include) +SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${EXECINFO_ROOT}/include) +SET(ENV{LIB} "$ENV{LIB}:${EXECINFO_ROOT}/lib") FIND_LIBRARY(EXECINFO NAMES execinfo) IF(EXECINFO) SET(LIBEXECINFO ${EXECINFO}) From 00816a964f42f65877c9f8982443b2522d09687d Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 2 Oct 2013 17:59:56 -0700 Subject: [PATCH 2/9] Fixed bug mdev-5028. Apparently in a general case a short-cut for the distinct optimization is invalid if join buffers are used to join tables after the tables whose values are to selected. --- mysql-test/r/distinct.result | 110 +++++++++++++++++++++++++++++++++++ mysql-test/t/distinct.test | 59 +++++++++++++++++++ sql/sql_cursor.cc | 2 +- sql/sql_select.cc | 11 ++-- sql/sql_select.h | 5 +- 5 files changed, 179 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index dc3b2fb1b47..b8343e70bf1 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -879,3 +879,113 @@ NULL 7 drop view v; drop table t1, t2; +CREATE TABLE t1 ( +id int, i1 int, i2 int DEFAULT 0, +d1 date DEFAULT '2000-01-01', d2 date DEFAULT '2000-01-01', +t1 time DEFAULT '00:00:00', t2 time DEFAULT '00:00:00', +dt1 datetime NOT NULL DEFAULT '2000-01-01 00:00:00', +dt2 datetime NOT NULL DEFAULT '2000-01-01 00:00:00', +c1 varchar(1) NOT NULL, c2 varchar(1) NOT NULL +) ENGINE=MyISAM; +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (id,i1,c1,c2) VALUES +(1,7,'t','t'),(2,4,'k','k'),(3,2,'e','e'),(4,0,'i','i'),(5,1,'t','t'),(6,91,'m','m'), +(7,6,'z','z'),(8,3,'c','c'),(9,6,'i','i'),(10,8,'v','v'), (11,1,'l','l'),(12,4,'j','j'), +(13,5,'w','w'),(14,0,'r','r'),(15,7,'o','o'),(16,9,'o','o'),(17,7,'u','u'),(18,6,'f','f'), +(19,0,'l','l'),(20,6,'g','g'),(21,1,'e','e'),(22,7,'y','y'),(23,0,'p','p'),(24,6,'v','v'), +(25,5,'d','d'),(26,9,'i','i'),(27,5,'z','z'),(28,2,'q','q'),(29,4,'j','j'),(30,9,'m','m'), +(31,8,'d','d'),(32,5,'r','r'),(33,1,'r','r'),(34,1,'k','k'),(35,4,'p','p'),(36,2,'x','x'), +(37,5,'w','w'),(38,0,'k','k'),(39,7,'y','y'),(40,4,'p','p'),(41,9,'l','l'),(42,2,'u','u'), +(43,3,'r','r'),(44,5,'y','y'),(45,3,'u','u'),(46,9,'t','t'),(47,8,'f','f'),(48,2,'f','f'), +(49,2,'q','q'),(50,6,'v','v'),(51,6,'u','u'),(52,0,'b','b'),(53,1,'n','n'),(54,2,'p','p'), +(55,0,'y','y'),(56,1,'l','l'),(57,1,'c','c'),(58,0,'d','d'),(59,2,'y','y'),(60,7,'l','l'), +(61,6,'m','m'),(62,9,'q','q'),(63,0,'j','j'),(64,3,'u','u'),(65,4,'w','w'),(66,5,'p','p'), +(67,8,'z','z'),(68,5,'u','u'),(69,7,'b','b'),(70,0,'f','f'),(71,6,'u','u'),(72,1,'i','i'), +(73,9,'s','s'),(74,3,'y','y'),(75,5,'s','s'),(76,8,'x','x'),(77,3,'s','s'),(78,3,'l','l'), +(79,8,'b','b'),(80,0,'p','p'),(81,9,'m','m'),(82,5,'k','k'),(83,7,'u','u'),(84,0,'y','y'), +(85,2,'x','x'),(86,5,'h','h'),(87,5,'j','j'),(88,5,'o','o'),(89,9,'o','o'),(90,1,'c','c'), +(91,7,'k','k'),(92,9,'t','t'),(93,3,'h','h'),(94,6,'g','g'),(95,9,'r','r'),(96,2,'i','i'); +CREATE TABLE t2 (i INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (7),(8); +SELECT STRAIGHT_JOIN COUNT(DISTINCT t1.id) FROM +t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; +COUNT(DISTINCT t1.id) +18 +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM +t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 96 100.00 Using where; Using temporary +1 PRIMARY ref key0 key0 5 test.t1.i1 9 100.00 Using where; Distinct +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where; Distinct; Using join buffer (flat, BNL join) +2 DERIVED t1 ALL NULL NULL NULL NULL 96 100.00 +Warnings: +Note 1003 select straight_join distinct `test`.`t1`.`id` AS `id` from `test`.`t1` join `test`.`v1` join `test`.`t2` where ((`test`.`t2`.`i` = `v1`.`id`) and (`v1`.`i1` = `test`.`t1`.`i1`) and (`v1`.`id` <> 3)) +set join_buffer_size=1024; +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM +t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; +id +7 +8 +9 +18 +20 +24 +43 +45 +50 +51 +61 +64 +71 +74 +77 +78 +93 +94 +set join_buffer_size=1024*16; +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM +t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; +id +7 +9 +18 +20 +24 +8 +50 +51 +61 +43 +45 +71 +64 +74 +77 +78 +94 +93 +set join_buffer_size=default; +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM +t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; +id +7 +9 +18 +20 +24 +50 +51 +61 +71 +94 +8 +43 +45 +64 +74 +77 +78 +93 +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index 302fb24f18c..9cdc79f1805 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -682,3 +682,62 @@ select * from v; select distinct (select max(a) from t1 where alias.b = a) as field1 from t2 as alias group by field1; drop view v; drop table t1, t2; + +# +# Bug mdev-5028: invalid distinct optimization when join buffer is used +# + +CREATE TABLE t1 ( + id int, i1 int, i2 int DEFAULT 0, + d1 date DEFAULT '2000-01-01', d2 date DEFAULT '2000-01-01', + t1 time DEFAULT '00:00:00', t2 time DEFAULT '00:00:00', + dt1 datetime NOT NULL DEFAULT '2000-01-01 00:00:00', + dt2 datetime NOT NULL DEFAULT '2000-01-01 00:00:00', + c1 varchar(1) NOT NULL, c2 varchar(1) NOT NULL +) ENGINE=MyISAM; + +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; + +INSERT INTO t1 (id,i1,c1,c2) VALUES +(1,7,'t','t'),(2,4,'k','k'),(3,2,'e','e'),(4,0,'i','i'),(5,1,'t','t'),(6,91,'m','m'), +(7,6,'z','z'),(8,3,'c','c'),(9,6,'i','i'),(10,8,'v','v'), (11,1,'l','l'),(12,4,'j','j'), +(13,5,'w','w'),(14,0,'r','r'),(15,7,'o','o'),(16,9,'o','o'),(17,7,'u','u'),(18,6,'f','f'), +(19,0,'l','l'),(20,6,'g','g'),(21,1,'e','e'),(22,7,'y','y'),(23,0,'p','p'),(24,6,'v','v'), +(25,5,'d','d'),(26,9,'i','i'),(27,5,'z','z'),(28,2,'q','q'),(29,4,'j','j'),(30,9,'m','m'), +(31,8,'d','d'),(32,5,'r','r'),(33,1,'r','r'),(34,1,'k','k'),(35,4,'p','p'),(36,2,'x','x'), +(37,5,'w','w'),(38,0,'k','k'),(39,7,'y','y'),(40,4,'p','p'),(41,9,'l','l'),(42,2,'u','u'), +(43,3,'r','r'),(44,5,'y','y'),(45,3,'u','u'),(46,9,'t','t'),(47,8,'f','f'),(48,2,'f','f'), +(49,2,'q','q'),(50,6,'v','v'),(51,6,'u','u'),(52,0,'b','b'),(53,1,'n','n'),(54,2,'p','p'), +(55,0,'y','y'),(56,1,'l','l'),(57,1,'c','c'),(58,0,'d','d'),(59,2,'y','y'),(60,7,'l','l'), +(61,6,'m','m'),(62,9,'q','q'),(63,0,'j','j'),(64,3,'u','u'),(65,4,'w','w'),(66,5,'p','p'), +(67,8,'z','z'),(68,5,'u','u'),(69,7,'b','b'),(70,0,'f','f'),(71,6,'u','u'),(72,1,'i','i'), +(73,9,'s','s'),(74,3,'y','y'),(75,5,'s','s'),(76,8,'x','x'),(77,3,'s','s'),(78,3,'l','l'), +(79,8,'b','b'),(80,0,'p','p'),(81,9,'m','m'),(82,5,'k','k'),(83,7,'u','u'),(84,0,'y','y'), +(85,2,'x','x'),(86,5,'h','h'),(87,5,'j','j'),(88,5,'o','o'),(89,9,'o','o'),(90,1,'c','c'), +(91,7,'k','k'),(92,9,'t','t'),(93,3,'h','h'),(94,6,'g','g'),(95,9,'r','r'),(96,2,'i','i'); + +CREATE TABLE t2 (i INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (7),(8); + +SELECT STRAIGHT_JOIN COUNT(DISTINCT t1.id) FROM + t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; + +EXPLAIN EXTENDED +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM + t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; + +set join_buffer_size=1024; +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM + t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; + +set join_buffer_size=1024*16; +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM + t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; + +set join_buffer_size=default; +SELECT STRAIGHT_JOIN DISTINCT t1.id FROM + t1, v1, t2 WHERE v1.id = t2.i AND t1.i1 = v1.i1 AND t2.i != 3; + +DROP VIEW v1; +DROP TABLE t1,t2; + diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index c171017a993..82751d64da9 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -398,7 +398,7 @@ Sensitive_cursor::open(JOIN *join_arg) #ifndef DBUG_OFF JOIN_TAB *first_tab= first_linear_tab(join, WITHOUT_CONST_TABLES); DBUG_ASSERT(first_tab->table->reginfo.not_exists_optimize == 0); - DBUG_ASSERT(first_tab->not_used_in_distinct == 0); + DBUG_ASSERT(first_tab->shortcut_for_distinct == 0); /* null_row is set only if row not found and it's outer join: should never happen for the first table in join_tab list diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 99157d9201b..bca53bef878 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1811,9 +1811,10 @@ int JOIN::init_execution() JOIN_TAB *last_join_tab= join_tab + top_join_tab_count - 1; do { - if (used_tables & last_join_tab->table->map) + if (used_tables & last_join_tab->table->map || + last_join_tab->use_join_cache) break; - last_join_tab->not_used_in_distinct=1; + last_join_tab->shortcut_for_distinct= true; } while (last_join_tab-- != join_tab); /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ if (order && skip_sort_order) @@ -7983,7 +7984,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) join_tab->last_inner= 0; join_tab->first_unmatched= 0; join_tab->ref.key = -1; - join_tab->not_used_in_distinct=0; + join_tab->shortcut_for_distinct= false; join_tab->read_first_record= join_init_read_record; join_tab->preread_init_done= FALSE; join_tab->join= this; @@ -16223,7 +16224,7 @@ static enum_nested_loop_state evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, int error) { - bool not_used_in_distinct=join_tab->not_used_in_distinct; + bool shortcut_for_distinct= join_tab->shortcut_for_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; bool select_cond_result= TRUE; @@ -16362,7 +16363,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, was not in the field list; In this case we can abort if we found a row, as no new rows can be added to the result. */ - if (not_used_in_distinct && found_records != join->found_records) + if (shortcut_for_distinct && found_records != join->found_records) DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); } else diff --git a/sql/sql_select.h b/sql/sql_select.h index 083302d1e4c..d75be9ae0fe 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -314,8 +314,9 @@ typedef struct st_join_table { uint used_null_fields; uint used_uneven_bit_fields; enum join_type type; - bool cached_eq_ref_table,eq_ref_table,not_used_in_distinct; - bool sorted; + bool cached_eq_ref_table,eq_ref_table; + bool shortcut_for_distinct; + bool sorted; /* If it's not 0 the number stored this field indicates that the index scan has been chosen to access the table data and we expect to scan From ec226e553aa56718ed9939e333fe36b3499ac9be Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 4 Oct 2013 09:51:07 -0700 Subject: [PATCH 3/9] Fixed bug mdev-5078. For aggregated fields from views/derived tables the possible adjustment of thd->lex->in_sum_func->max_arg_level in the function Item_field::fix_fields must be done before we leave the function. --- mysql-test/r/derived_view.result | 18 ++++++++++++++++++ mysql-test/t/derived_view.test | 19 +++++++++++++++++++ sql/item.cc | 10 +++++----- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index 8853338ca8d..eb2200c7720 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -2205,6 +2205,24 @@ DROP VIEW v1; DROP TABLE t1,t2; set optimizer_switch=@save_optimizer_switch; # +# mdev-5078: sum over a view/derived table +# +CREATE TABLE t1 (a int); +INSERT INTO t1 (a) VALUES (1), (2); +CREATE TABLE t2 (b int(11)); +INSERT INTO t2 (b) VALUES (1), (2); +CREATE VIEW v AS SELECT b as c FROM t2; +SELECT a, (SELECT SUM(a + c) FROM v) FROM t1; +a (SELECT SUM(a + c) FROM v) +1 5 +2 7 +SELECT a, (SELECT SUM(a + c) FROM (SELECT b as c FROM t2) AS v1) FROM t1; +a (SELECT SUM(a + c) FROM (SELECT b as c FROM t2) AS v1) +1 5 +2 7 +DROP VIEW v; +DROP TABLE t1,t2; +# # end of 5.3 tests # set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index 4b7e76e11ca..254f97ebe6a 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -1545,6 +1545,25 @@ DROP TABLE t1,t2; set optimizer_switch=@save_optimizer_switch; +--echo # +--echo # mdev-5078: sum over a view/derived table +--echo # + +CREATE TABLE t1 (a int); +INSERT INTO t1 (a) VALUES (1), (2); + +CREATE TABLE t2 (b int(11)); +INSERT INTO t2 (b) VALUES (1), (2); + +CREATE VIEW v AS SELECT b as c FROM t2; + +SELECT a, (SELECT SUM(a + c) FROM v) FROM t1; + +SELECT a, (SELECT SUM(a + c) FROM (SELECT b as c FROM t2) AS v1) FROM t1; + +DROP VIEW v; +DROP TABLE t1,t2; + --echo # --echo # end of 5.3 tests --echo # diff --git a/sql/item.cc b/sql/item.cc index 9738a068d88..803c9fee576 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4746,6 +4746,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) goto mark_non_agg_field; } + if (thd->lex->in_sum_func && + thd->lex->in_sum_func->nest_level == + thd->lex->current_select->nest_level) + set_if_bigger(thd->lex->in_sum_func->max_arg_level, + thd->lex->current_select->nest_level); /* if it is not expression from merged VIEW we will set this field. @@ -4762,11 +4767,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference) return FALSE; set_field(from_field); - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level == - thd->lex->current_select->nest_level) - set_if_bigger(thd->lex->in_sum_func->max_arg_level, - thd->lex->current_select->nest_level); } else if (thd->mark_used_columns != MARK_COLUMNS_NONE) { From ae826010351ab69a056034769124f3dac67a3de7 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 9 Oct 2013 17:30:50 +0500 Subject: [PATCH 4/9] MDEV-3856 Import of a large polygon fails/hangs. The Gis_point::init_from_wkt called the String::realloc(), and this call is quite slow in the DEBUG mode. Which makes loading the huge polygon hang forever. Fixed by using the String::realloc(size, inc_size) version instead as it's done for other spatial features. --- sql/spatial.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/spatial.cc b/sql/spatial.cc index 32a2012a49d..1d4051487ae 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -480,7 +480,7 @@ bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb) { double x, y; if (trs->get_next_number(&x) || trs->get_next_number(&y) || - wkb->reserve(POINT_DATA_SIZE)) + wkb->reserve(POINT_DATA_SIZE, 512)) return 1; wkb->q_append(x); wkb->q_append(y); From 508d40fbdbe02c390f102d991ce0675f519784dd Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 10 Oct 2013 14:20:35 +0500 Subject: [PATCH 5/9] MDEV-4788 check mysql-5.5 changes in spatial.cc. Additional patch for the 5.5. --- sql/spatial.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/spatial.cc b/sql/spatial.cc index 1d4051487ae..b82e6977f8a 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -793,7 +793,7 @@ int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const return 1; n_points= uint4korr(data); data+= 4; - if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points)) + if (n_points < 1 || not_enough_points(data, n_points)) return 1; trn->start_line(); @@ -1230,7 +1230,7 @@ int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const return 1; n_points= uint4korr(data); data+= 4; - if (!n_points || no_data(data, POINT_DATA_SIZE * n_points)) + if (!n_points || not_enough_points(data, n_points)) return 1; trn->start_ring(); From 7c87385e3075143de18e50c1d327eeb2e224603a Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 10 Oct 2013 10:08:26 -0700 Subject: [PATCH 6/9] Fixed bug mdev-5105. The bug caused a memory overwrite in the function update_ref_and_keys() It happened due to a wrong value of SELECT_LEX::cond_count. This value historically was calculated by the fix_fields method. Now the logic of calling this method became too complicated and, as a result, this value is calculated not always correctly. The patch changes the way how and when the values of SELECT_LEX::cond_count and of SELECT_LEX::between_count are calculated. The new code does it just at the beginning of update_ref_and_keys(). --- mysql-test/r/derived_view.result | 11 +++++++++++ mysql-test/t/derived_view.test | 14 ++++++++++++++ sql/item.h | 1 + sql/item_cmpfunc.cc | 25 ++++++++++++++++++++++++ sql/item_cmpfunc.h | 4 +++- sql/item_func.cc | 10 ++++++++++ sql/item_func.h | 5 ++++- sql/sql_base.cc | 1 - sql/sql_derived.cc | 2 -- sql/sql_select.cc | 33 ++++++++++++++++++++++++++------ 10 files changed, 95 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index eb2200c7720..0278c36b557 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -2223,6 +2223,17 @@ a (SELECT SUM(a + c) FROM (SELECT b as c FROM t2) AS v1) DROP VIEW v; DROP TABLE t1,t2; # +# mdev-5105: memory overwrite in multi-table update +# using natuaral join with a view +# +create table t1(a int,b tinyint,c tinyint)engine=myisam; +create table t2(a tinyint,b float,c int, d int, e int, f int, key (b), key(c), key(d), key(e), key(f))engine=myisam; +create table t3(a int,b int,c int, d int, e int, f int, key(a), key(b), key(c), key(d), key(e), key(f))engine=myisam; +create view v1 as select t2.b a, t1.b b, t2.c c, t2.d d, t2.e e, t2.f f from t1,t2 where t1.a=t2.a; +update t3 natural join v1 set a:=1; +drop view v1; +drop table t1,t2,t3; +# # end of 5.3 tests # set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index 254f97ebe6a..8d1b3109d20 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -1564,6 +1564,20 @@ SELECT a, (SELECT SUM(a + c) FROM (SELECT b as c FROM t2) AS v1) FROM t1; DROP VIEW v; DROP TABLE t1,t2; +--echo # +--echo # mdev-5105: memory overwrite in multi-table update +--echo # using natuaral join with a view +--echo # + +create table t1(a int,b tinyint,c tinyint)engine=myisam; +create table t2(a tinyint,b float,c int, d int, e int, f int, key (b), key(c), key(d), key(e), key(f))engine=myisam; +create table t3(a int,b int,c int, d int, e int, f int, key(a), key(b), key(c), key(d), key(e), key(f))engine=myisam; +create view v1 as select t2.b a, t1.b b, t2.c c, t2.d d, t2.e e, t2.f f from t1,t2 where t1.a=t2.a; + +update t3 natural join v1 set a:=1; +drop view v1; +drop table t1,t2,t3; + --echo # --echo # end of 5.3 tests --echo # diff --git a/sql/item.h b/sql/item.h index fd19180f3be..4f03d588bbc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1054,6 +1054,7 @@ public: virtual bool view_used_tables_processor(uchar *arg) { return 0; } virtual bool eval_not_null_tables(uchar *opt_arg) { return 0; } virtual bool is_subquery_processor (uchar *opt_arg) { return 0; } + virtual bool count_sargable_conds(uchar *arg) { return 0; } virtual bool limit_index_condition_pushdown_processor(uchar *opt_arg) { return FALSE; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a6587fd4c3d..514b0fe4580 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -539,6 +539,8 @@ void Item_bool_func2::fix_length_and_dec() to the collation of A. */ + sargable= true; + DTCollation coll; if (args[0]->result_type() == STRING_RESULT && args[1]->result_type() == STRING_RESULT && @@ -1433,6 +1435,7 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg) return FALSE; } + bool Item_in_optimizer::fix_left(THD *thd, Item **ref) { if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) || @@ -2160,6 +2163,15 @@ bool Item_func_between::eval_not_null_tables(uchar *opt_arg) } +bool Item_func_between::count_sargable_conds(uchar *arg) +{ + SELECT_LEX *sel= (SELECT_LEX *) arg; + sel->cond_count++; + sel->between_count++; + return 0; +} + + void Item_func_between::fix_after_pullout(st_select_lex *new_parent, Item **ref) { /* This will re-calculate attributes of the arguments */ @@ -2173,6 +2185,7 @@ void Item_func_between::fix_length_and_dec() THD *thd= current_thd; max_length= 1; compare_as_dates= 0; + sargable= true; /* As some compare functions are generated after sql_yacc, @@ -3852,6 +3865,7 @@ void Item_func_in::fix_length_and_dec() uint found_types= 0; uint type_cnt= 0, i; Item_result cmp_type= STRING_RESULT; + sargable= true; left_result_type= args[0]->cmp_type(); if (!(found_types= collect_cmp_types(args, arg_count, true))) return; @@ -4638,6 +4652,7 @@ longlong Item_func_isnull::val_int() return args[0]->is_null() ? 1: 0; } + longlong Item_is_not_null_test::val_int() { DBUG_ASSERT(fixed == 1); @@ -4841,6 +4856,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) return FALSE; } + void Item_func_like::cleanup() { canDoTurboBM= FALSE; @@ -5868,6 +5884,14 @@ void Item_equal::update_used_tables() } +bool Item_equal::count_sargable_conds(uchar *arg) +{ + SELECT_LEX *sel= (SELECT_LEX *) arg; + uint m= equal_items.elements; + sel->cond_count+= m*(m-1); + return 0; +} + /** @brief @@ -5920,6 +5944,7 @@ void Item_equal::fix_length_and_dec() Item *item= get_first(NO_PARTICULAR_TAB, NULL); eval_item= cmp_item::get_comparator(item->cmp_type(), item, item->collation.collation); + sargable= true; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 99d89e16532..4deda7679ac 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -118,7 +118,7 @@ public: Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {} Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} bool is_bool_func() { return 1; } - void fix_length_and_dec() { decimals=0; max_length=1; } + void fix_length_and_dec() { decimals=0; max_length=1; sargable= true;} uint decimal_precision() const { return 1; } }; @@ -681,6 +681,7 @@ public: uint decimal_precision() const { return 1; } bool eval_not_null_tables(uchar *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref); + bool count_sargable_conds(uchar *arg); }; @@ -1747,6 +1748,7 @@ public: CHARSET_INFO *compare_collation(); void set_context_field(Item_field *ctx_field) { context_field= ctx_field; } + bool count_sargable_conds(uchar *arg); friend class Item_equal_iterator; friend class Item_equal_iterator; friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, diff --git a/sql/item_func.cc b/sql/item_func.cc index c729893dae0..9416d05cb2f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -733,6 +733,16 @@ double Item_int_func::val_real() return unsigned_flag ? (double) ((ulonglong) val_int()) : (double) val_int(); } +bool Item_int_func::count_sargable_conds(uchar *arg) +{ + if (sargable) + { + SELECT_LEX *sel= (SELECT_LEX *) arg; + sel->cond_count++; + } + return 0; +} + String *Item_int_func::val_str(String *str) { diff --git a/sql/item_func.h b/sql/item_func.h index 80b794f30d5..310b312d1e4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -485,6 +485,8 @@ class Item_num_op :public Item_func_numhybrid class Item_int_func :public Item_func { +protected: + bool sargable; public: Item_int_func() :Item_func() { max_length= 21; } Item_int_func(Item *a) :Item_func(a) { max_length= 21; } @@ -496,7 +498,8 @@ public: double val_real(); String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } - void fix_length_and_dec() {} + void fix_length_and_dec() { sargable= false; } + bool count_sargable_conds(uchar *arg); }; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 22dc09351c7..130763de76a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8549,7 +8549,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List &leaves, embedded->on_expr->fix_fields(thd, &embedded->on_expr)) || embedded->on_expr->check_cols(1)) goto err_no_arena; - select_lex->cond_count++; } /* If it's a semi-join nest, fix its "left expression", as it is used by diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index a8bfc8a11a7..db6ab1fb269 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -394,8 +394,6 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) if (dt_select->options & OPTION_SCHEMA_TABLE) parent_lex->options |= OPTION_SCHEMA_TABLE; - parent_lex->cond_count+= dt_select->cond_count; - if (!derived->get_unit()->prepared) { dt_select->leaf_tables.empty(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bca53bef878..072f10a4d08 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4733,6 +4733,32 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, KEY_FIELD *key_fields, *end, *field; uint sz; uint m= max(select_lex->max_equal_elems,1); + + SELECT_LEX *sel=thd->lex->current_select; + sel->cond_count= 0; + sel->between_count= 0; + if (cond) + cond->walk(&Item::count_sargable_conds, 0, (uchar*) sel); + for (i=0 ; i < tables ; i++) + { + if (*join_tab[i].on_expr_ref) + (*join_tab[i].on_expr_ref)->walk(&Item::count_sargable_conds, + 0, (uchar*) sel); + } + { + List_iterator li(*join_tab->join->join_list); + TABLE_LIST *table; + while ((table= li++)) + { + if (table->nested_join) + { + if (table->on_expr) + table->on_expr->walk(&Item::count_sargable_conds, 0, (uchar*) sel); + if (table->sj_on_expr) + table->sj_on_expr->walk(&Item::count_sargable_conds, 0, (uchar*) sel); + } + } + } /* We use the same piece of memory to store both KEY_FIELD @@ -4756,8 +4782,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, substitutions. */ sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))* - (((thd->lex->current_select->cond_count+1)*2 + - thd->lex->current_select->between_count)*m+1); + ((sel->cond_count*2 + sel->between_count)*m+1); if (!(key_fields=(KEY_FIELD*) thd->alloc(sz))) return TRUE; /* purecov: inspected */ and_level= 0; @@ -11219,13 +11244,10 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row, (Item_row *) left_item, (Item_row *) right_item, cond_equal, eq_list); - if (!is_converted) - thd->lex->current_select->cond_count++; } else { is_converted= check_simple_equality(left_item, right_item, 0, cond_equal); - thd->lex->current_select->cond_count++; } if (!is_converted) @@ -11284,7 +11306,6 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, if (left_item->type() == Item::ROW_ITEM && right_item->type() == Item::ROW_ITEM) { - thd->lex->current_select->cond_count--; return check_row_equality(thd, (Item_row *) left_item, (Item_row *) right_item, From 092a238864591bc540beb00145759fa6af5f2746 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 11 Oct 2013 12:50:30 -0700 Subject: [PATCH 7/9] Fixed a problem of the patch for mdev-5105 that caused valgrind complains. --- sql/item_func.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sql/item_func.h b/sql/item_func.h index 310b312d1e4..b3ce85b96c4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -488,17 +488,20 @@ class Item_int_func :public Item_func protected: bool sargable; public: - Item_int_func() :Item_func() { max_length= 21; } - Item_int_func(Item *a) :Item_func(a) { max_length= 21; } - Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length= 21; } + Item_int_func() :Item_func() { max_length= 21; sargable= false; } + Item_int_func(Item *a) :Item_func(a) { max_length= 21; sargable= false; } + Item_int_func(Item *a,Item *b) :Item_func(a,b) + { max_length= 21; sargable= false; } Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) - { max_length= 21; } - Item_int_func(List &list) :Item_func(list) { max_length= 21; } - Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {} + { max_length= 21; sargable= false; } + Item_int_func(List &list) :Item_func(list) + { max_length= 21; sargable= false; } + Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) + { sargable= false;} double val_real(); String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } - void fix_length_and_dec() { sargable= false; } + void fix_length_and_dec() {} bool count_sargable_conds(uchar *arg); }; From 78b580b77965d63d4292a72a3ba12d0cc83b01a3 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 11 Oct 2013 23:24:57 -0700 Subject: [PATCH 8/9] Fixed bug mdev-5132. Objects of the classes Item_func_isnull and Item_func_isnotnull must have the flag sargable set to TRUE. Set the value of the flag sargable only in constructors of the classes inherited from Item_int_func. --- mysql-test/r/null.result | 9 +++++++++ mysql-test/t/null.test | 12 ++++++++++++ sql/item_cmpfunc.cc | 9 +++------ sql/item_cmpfunc.h | 17 ++++++++++------- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index e62ba68c8f6..fe7ed32cbb0 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -373,3 +373,12 @@ id select_type table type possible_keys key key_len ref rows Extra SELECT * FROM t1 WHERE NOT (concat( dt, '1' ) IS NOT NULL); dt DROP TABLE t1; +# +# Bug mdev-5132: crash when exeicuting a join query +# with IS NULL and IS NOT NULL in where +# +CREATE TABLE t1 (a DATE, b INT, c INT, KEY(a), KEY(b), KEY(c)) ENGINE=MyISAM; +CREATE TABLE t2 (d DATE) ENGINE=MyISAM; +SELECT * FROM t1,t2 WHERE 1 IS NOT NULL AND t1.b IS NULL; +a b c d +DROP TABLE t1,t2; diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test index 4a45240ec68..81951a9ce68 100644 --- a/mysql-test/t/null.test +++ b/mysql-test/t/null.test @@ -283,3 +283,15 @@ SELECT * FROM t1 WHERE NOT (concat( dt, '1' ) IS NOT NULL); SELECT * FROM t1 WHERE NOT (concat( dt, '1' ) IS NOT NULL); DROP TABLE t1; + +--echo # +--echo # Bug mdev-5132: crash when exeicuting a join query +--echo # with IS NULL and IS NOT NULL in where +--echo # + +CREATE TABLE t1 (a DATE, b INT, c INT, KEY(a), KEY(b), KEY(c)) ENGINE=MyISAM; +CREATE TABLE t2 (d DATE) ENGINE=MyISAM; + +SELECT * FROM t1,t2 WHERE 1 IS NOT NULL AND t1.b IS NULL; + +DROP TABLE t1,t2; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 514b0fe4580..d1075c3c47f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -539,8 +539,6 @@ void Item_bool_func2::fix_length_and_dec() to the collation of A. */ - sargable= true; - DTCollation coll; if (args[0]->result_type() == STRING_RESULT && args[1]->result_type() == STRING_RESULT && @@ -2185,7 +2183,6 @@ void Item_func_between::fix_length_and_dec() THD *thd= current_thd; max_length= 1; compare_as_dates= 0; - sargable= true; /* As some compare functions are generated after sql_yacc, @@ -3865,7 +3862,6 @@ void Item_func_in::fix_length_and_dec() uint found_types= 0; uint type_cnt= 0, i; Item_result cmp_type= STRING_RESULT; - sargable= true; left_result_type= args[0]->cmp_type(); if (!(found_types= collect_cmp_types(args, arg_count, true))) return; @@ -5491,7 +5487,8 @@ Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item) equal_items.push_back(f1); equal_items.push_back(f2); compare_as_dates= with_const_item && f2->cmp_type() == TIME_RESULT; - upper_levels= NULL; + upper_levels= NULL; + sargable= TRUE; } @@ -5521,6 +5518,7 @@ Item_equal::Item_equal(Item_equal *item_equal) compare_as_dates= item_equal->compare_as_dates; cond_false= item_equal->cond_false; upper_levels= item_equal->upper_levels; + sargable= TRUE; } @@ -5944,7 +5942,6 @@ void Item_equal::fix_length_and_dec() Item *item= get_first(NO_PARTICULAR_TAB, NULL); eval_item= cmp_item::get_comparator(item->cmp_type(), item, item->collation.collation); - sargable= true; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 4deda7679ac..c1ef680f3ee 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -118,7 +118,7 @@ public: Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {} Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} bool is_bool_func() { return 1; } - void fix_length_and_dec() { decimals=0; max_length=1; sargable= true;} + void fix_length_and_dec() { decimals=0; max_length=1; } uint decimal_precision() const { return 1; } }; @@ -364,7 +364,8 @@ protected: public: Item_bool_func2(Item *a,Item *b) - :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), abort_on_null(FALSE) {} + :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), + abort_on_null(FALSE) { sargable= TRUE; } void fix_length_and_dec(); void set_cmp_func() { @@ -668,7 +669,7 @@ public: /* TRUE <=> arguments will be compared as dates. */ Item *compare_as_dates; Item_func_between(Item *a, Item *b, Item *c) - :Item_func_opt_neg(a, b, c), compare_as_dates(FALSE) {} + :Item_func_opt_neg(a, b, c), compare_as_dates(FALSE) { sargable= TRUE; } longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_KEY; } enum Functype functype() const { return BETWEEN; } @@ -1280,10 +1281,11 @@ public: Item_func_in(List &list) :Item_func_opt_neg(list), array(0), have_null(0), - arg_types_compatible(FALSE) + arg_types_compatible(FALSE) { bzero(&cmp_items, sizeof(cmp_items)); allowed_arg_cols= 0; // Fetch this value from first argument + sargable= TRUE; } longlong val_int(); bool fix_fields(THD *, Item **); @@ -1349,7 +1351,7 @@ public: class Item_func_isnull :public Item_bool_func { public: - Item_func_isnull(Item *a) :Item_bool_func(a) {} + Item_func_isnull(Item *a) :Item_bool_func(a) { sargable= TRUE; } longlong val_int(); enum Functype functype() const { return ISNULL_FUNC; } void fix_length_and_dec() @@ -1410,7 +1412,8 @@ class Item_func_isnotnull :public Item_bool_func { bool abort_on_null; public: - Item_func_isnotnull(Item *a) :Item_bool_func(a), abort_on_null(0) {} + Item_func_isnotnull(Item *a) :Item_bool_func(a), abort_on_null(0) + { sargable= TRUE; } longlong val_int(); enum Functype functype() const { return ISNOTNULL_FUNC; } void fix_length_and_dec() @@ -1717,7 +1720,7 @@ public: inline Item_equal() : Item_bool_func(), with_const(FALSE), eval_item(0), cond_false(0), context_field(NULL) - { const_item_cache=0 ;} + { const_item_cache=0; sargable= TRUE; } Item_equal(Item *f1, Item *f2, bool with_const_item); Item_equal(Item_equal *item_equal); /* Currently the const item is always the first in the list of equal items */ From e37639e9349b56296d452e69e970df939383d7e1 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 13 Oct 2013 23:25:57 +0500 Subject: [PATCH 9/9] MDEV-5131 create_embedded_thd is not thread safe, libmysqld. LOCK_thread_count locked when we do threads.append(). --- libmysqld/lib_sql.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 88f8f039ce2..d5e5ecca2f5 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -683,8 +683,10 @@ void *create_embedded_thd(int client_flag) thd->data_tail= &thd->first_data; bzero((char*) &thd->net, sizeof(thd->net)); + mysql_mutex_lock(&LOCK_thread_count); thread_count++; threads.append(thd); + mysql_mutex_unlock(&LOCK_thread_count); thd->mysys_var= 0; return thd; err: