From c32f62bebb609f6a0c2c91c303c15a482a5b28d3 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/deer.(none)" <> Date: Mon, 4 Sep 2006 19:47:24 +0500 Subject: [PATCH 01/28] bug #12620 (UTF-8 indexing causes ER_NO_KEYFILE error) The problem is that on some Mac OS X-es the file writing/reading call with zero bytes to read/write returns error. So here i try to eliminate that kinds of calls. --- myisam/mi_check.c | 9 ++++++--- mysys/my_chsize.c | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 1e62e5e641d..65ce70a97df 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -1366,7 +1366,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, param->temp_filename); goto err; } - if (filecopy(param,new_file,info->dfile,0L,new_header_length, + if (new_header_length && + filecopy(param,new_file,info->dfile,0L,new_header_length, "datafile-header")) goto err; info->s->state.dellink= HA_OFFSET_ERROR; @@ -2063,7 +2064,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, param->temp_filename); goto err; } - if (filecopy(param, new_file,info->dfile,0L,new_header_length, + if (new_header_length && + filecopy(param, new_file,info->dfile,0L,new_header_length, "datafile-header")) goto err; if (param->testflag & T_UNPACK) @@ -2431,7 +2433,8 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, param->temp_filename); goto err; } - if (filecopy(param, new_file,info->dfile,0L,new_header_length, + if (new_header_length && + filecopy(param, new_file,info->dfile,0L,new_header_length, "datafile-header")) goto err; if (param->testflag & T_UNPACK) diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c index cf26428d65f..efc19927183 100644 --- a/mysys/my_chsize.c +++ b/mysys/my_chsize.c @@ -44,7 +44,9 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags) DBUG_PRINT("my",("fd: %d length: %lu MyFlags: %d",fd,(ulong) newlength, MyFlags)); - oldsize = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE)); + if ((oldsize = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE))) == newlength) + DBUG_RETURN(0); + DBUG_PRINT("info",("old_size: %ld", (ulong) oldsize)); if (oldsize > newlength) From 668a57b10a2556f1d90de54b71cc379b536ca965 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/deer.(none)" <> Date: Wed, 6 Sep 2006 19:56:19 +0500 Subject: [PATCH 02/28] bug #12991 (compile error --without-geometry) --- myisam/mi_check.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 1e62e5e641d..1374cb05094 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -1153,9 +1153,12 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) /* We don't need to lock the key tree here as we don't allow concurrent threads when running myisamchk */ - int search_result= (keyinfo->flag & HA_SPATIAL) ? + int search_result= +#ifdef HAVE_RTREE_KEYS + (keyinfo->flag & HA_SPATIAL) ? rtree_find_first(info, key, info->lastkey, key_length, MBR_EQUAL | MBR_DATA) : +#endif _mi_search(info,keyinfo,info->lastkey,key_length, SEARCH_SAME, info->s->state.key_root[key]); if (search_result) From 5bc16fd9545a92ba2690ab0687e6bdf76d92757a Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Fri, 8 Sep 2006 19:04:46 +0300 Subject: [PATCH 03/28] Bug #21540: Subqueries with no from and aggregate functions return wrong results Mark the containing Item(s) (Item_subselect descendant usually) of a subselect as containing aggregate functions if it has references to aggregates functions that are calculated outside its context. This tels end_send_group() not to make an Item_subselect descendant in select list a copy and causes the correct value being returned. --- mysql-test/r/func_group.result | 2 +- mysql-test/r/subselect.result | 61 ++++++++++++++++++++++++++++++++++ mysql-test/t/subselect.test | 31 +++++++++++++++++ sql/item_sum.cc | 22 +++++++++++- 4 files changed, 114 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index f57b4ad6ce9..da2a7518c86 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -997,7 +997,7 @@ SELECT SQL_NO_CACHE WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid FROM t1 t, t2 c WHERE t.a = c.b; minid -NULL +1 DROP TABLE t1,t2; create table t1 select variance(0); show create table t1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 4ee6d3088a5..a6fb9a3eb61 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3368,3 +3368,64 @@ ORDER BY t1.t DESC LIMIT 1); i1 i2 t i1 i2 t 24 1 2005-05-27 12:40:30 24 1 2006-06-20 12:29:40 DROP TABLE t1, t2; +CREATE TABLE t1 (a INT, b INT); +CREATE TABLE t2 (a INT); +INSERT INTO t2 values (1); +INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(3,4); +SELECT (SELECT COUNT(DISTINCT t1.b) from t2) FROM t1 GROUP BY t1.a; +(SELECT COUNT(DISTINCT t1.b) from t2) +2 +1 +1 +SELECT (SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3) +FROM t1 GROUP BY t1.a; +(SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3) +2 +1 +1 +SELECT COUNT(DISTINCT t1.b), (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a; +COUNT(DISTINCT t1.b) (SELECT COUNT(DISTINCT t1.b)) +2 2 +1 1 +1 1 +SELECT COUNT(DISTINCT t1.b), +(SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3) +FROM t1 GROUP BY t1.a; +COUNT(DISTINCT t1.b) (SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3) +2 2 +1 1 +1 1 +SELECT ( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +FROM t1 GROUP BY t1.a; +( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +2 +1 +1 +SELECT ( +SELECT ( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +FROM t1 GROUP BY t1.a LIMIT 1) +FROM t1 t2 +GROUP BY t2.a; +( +SELECT ( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +FROM t1 GROUP BY t1.a LIMIT 1) +2 +2 +2 +DROP TABLE t1,t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index ed122e9ff5a..4d0bb9fd6c6 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2280,3 +2280,34 @@ SELECT * FROM t1,t2 ORDER BY t1.t DESC LIMIT 1); DROP TABLE t1, t2; + +# +# Bug #21540: Subqueries with no from and aggregate functions return +# wrong results +CREATE TABLE t1 (a INT, b INT); +CREATE TABLE t2 (a INT); +INSERT INTO t2 values (1); +INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(3,4); +SELECT (SELECT COUNT(DISTINCT t1.b) from t2) FROM t1 GROUP BY t1.a; +SELECT (SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3) + FROM t1 GROUP BY t1.a; +SELECT COUNT(DISTINCT t1.b), (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a; +SELECT COUNT(DISTINCT t1.b), + (SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3) + FROM t1 GROUP BY t1.a; +SELECT ( + SELECT ( + SELECT COUNT(DISTINCT t1.b) + ) +) +FROM t1 GROUP BY t1.a; +SELECT ( + SELECT ( + SELECT ( + SELECT COUNT(DISTINCT t1.b) + ) + ) + FROM t1 GROUP BY t1.a LIMIT 1) +FROM t1 t2 +GROUP BY t2.a; +DROP TABLE t1,t2; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0d2a5b3b080..7dc90b11771 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -246,7 +246,27 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) aggr_sl->inner_sum_func_list->next= this; } aggr_sl->inner_sum_func_list= this; - + aggr_sl->with_sum_func= 1; + + /* + Mark Item_subselect(s) as containing aggregate function all the way up + to aggregate function's calculation context. + Note that we must not mark the Item of calculation context itself + because with_sum_func on the calculation context st_select_lex is + already set above. + + with_sum_func being set for an Item means that this Item refers + (somewhere in it, e.g. one of its arguments if it's a function) directly + or through intermediate items to an aggregate function that is calculated + in a context "outside" of the Item (e.g. in the current or outer select). + + with_sum_func being set for an st_select_lex means that this st_select_lex + has aggregate functions directly referenced (i.e. not through a sub-select). + */ + for (sl= thd->lex->current_select; + sl && sl != aggr_sl && sl->master_unit()->item; + sl= sl->master_unit()->outer_select() ) + sl->master_unit()->item->with_sum_func= 1; } return FALSE; } From dd3b8e4f9aac1f724671b142b86da274157ae8d8 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sat, 16 Sep 2006 11:50:00 -0700 Subject: [PATCH 04/28] Fixed bug #22085: Crash on the execution of a prepared statement that uses an aggregating IN subquery with HAVING clause. A wrong order of the call of split_sum_func2 for the HAVING clause of the subquery and the transformation for the subquery resulted in the creation of a andor structure that could not be restored at an execution of the prepared statement. --- mysql-test/r/ps.result | 47 ++++++++++++++++++++++++++++++++++++++ mysql-test/t/ps.test | 52 ++++++++++++++++++++++++++++++++++++++++++ sql/sql_select.cc | 5 ++-- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 01aa4ddf859..78752622db7 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -889,3 +889,50 @@ create temporary table if not exists t1 (a1 int); execute stmt; drop temporary table t1; deallocate prepare stmt; +CREATE TABLE t1( +ID int(10) unsigned NOT NULL auto_increment, +Member_ID varchar(15) NOT NULL default '', +Action varchar(12) NOT NULL, +Action_Date datetime NOT NULL, +Track varchar(15) default NULL, +User varchar(12) default NULL, +Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update +CURRENT_TIMESTAMP, +PRIMARY KEY (ID), +KEY Action (Action), +KEY Action_Date (Action_Date) +); +INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES +('111111', 'Disenrolled', '2006-03-01', 'CAD' ), +('111111', 'Enrolled', '2006-03-01', 'CAD' ), +('111111', 'Disenrolled', '2006-07-03', 'CAD' ), +('222222', 'Enrolled', '2006-03-07', 'CAD' ), +('222222', 'Enrolled', '2006-03-07', 'CHF' ), +('222222', 'Disenrolled', '2006-08-02', 'CHF' ), +('333333', 'Enrolled', '2006-03-01', 'CAD' ), +('333333', 'Disenrolled', '2006-03-01', 'CAD' ), +('444444', 'Enrolled', '2006-03-01', 'CAD' ), +('555555', 'Disenrolled', '2006-03-01', 'CAD' ), +('555555', 'Enrolled', '2006-07-21', 'CAD' ), +('555555', 'Disenrolled', '2006-03-01', 'CHF' ), +('666666', 'Enrolled', '2006-02-09', 'CAD' ), +('666666', 'Enrolled', '2006-05-12', 'CHF' ), +('666666', 'Disenrolled', '2006-06-01', 'CAD' ); +PREPARE STMT FROM +"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 + WHERE Member_ID=? AND Action='Enrolled' AND + (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 + WHERE Member_ID=? + GROUP BY Track + HAVING Track>='CAD' AND + MAX(Action_Date)>'2006-03-01')"; +SET @id='111111'; +EXECUTE STMT USING @id,@id; +GROUP_CONCAT(Track SEPARATOR ', ') +NULL +SET @id='222222'; +EXECUTE STMT USING @id,@id; +GROUP_CONCAT(Track SEPARATOR ', ') +CAD +DEALLOCATE PREPARE STMT; +DROP TABLE t1; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 0ca293eb1ba..7c2a42404ad 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -951,4 +951,56 @@ execute stmt; drop temporary table t1; deallocate prepare stmt; +# +# BUG#22085: Crash on the execution of a prepared statement that +# uses an IN subquery with aggregate functions in HAVING +# + +CREATE TABLE t1( + ID int(10) unsigned NOT NULL auto_increment, + Member_ID varchar(15) NOT NULL default '', + Action varchar(12) NOT NULL, + Action_Date datetime NOT NULL, + Track varchar(15) default NULL, + User varchar(12) default NULL, + Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update + CURRENT_TIMESTAMP, + PRIMARY KEY (ID), + KEY Action (Action), + KEY Action_Date (Action_Date) +); + +INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES + ('111111', 'Disenrolled', '2006-03-01', 'CAD' ), + ('111111', 'Enrolled', '2006-03-01', 'CAD' ), + ('111111', 'Disenrolled', '2006-07-03', 'CAD' ), + ('222222', 'Enrolled', '2006-03-07', 'CAD' ), + ('222222', 'Enrolled', '2006-03-07', 'CHF' ), + ('222222', 'Disenrolled', '2006-08-02', 'CHF' ), + ('333333', 'Enrolled', '2006-03-01', 'CAD' ), + ('333333', 'Disenrolled', '2006-03-01', 'CAD' ), + ('444444', 'Enrolled', '2006-03-01', 'CAD' ), + ('555555', 'Disenrolled', '2006-03-01', 'CAD' ), + ('555555', 'Enrolled', '2006-07-21', 'CAD' ), + ('555555', 'Disenrolled', '2006-03-01', 'CHF' ), + ('666666', 'Enrolled', '2006-02-09', 'CAD' ), + ('666666', 'Enrolled', '2006-05-12', 'CHF' ), + ('666666', 'Disenrolled', '2006-06-01', 'CAD' ); + +PREPARE STMT FROM +"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 + WHERE Member_ID=? AND Action='Enrolled' AND + (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 + WHERE Member_ID=? + GROUP BY Track + HAVING Track>='CAD' AND + MAX(Action_Date)>'2006-03-01')"; +SET @id='111111'; +EXECUTE STMT USING @id,@id; +SET @id='222222'; +EXECUTE STMT USING @id,@id; + +DEALLOCATE PREPARE STMT; +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5154bff78dd..62eb5235d70 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -290,8 +290,6 @@ JOIN::prepare(Item ***rref_pointer_array, select_lex->having_fix_field= 0; if (having_fix_rc || thd->net.report_error) DBUG_RETURN(-1); /* purecov: inspected */ - if (having->with_sum_func) - having->split_sum_func2(thd, ref_pointer_array, all_fields, &having); } // Is it subselect @@ -306,6 +304,9 @@ JOIN::prepare(Item ***rref_pointer_array, } } + if (having && having->with_sum_func) + having->split_sum_func2(thd, ref_pointer_array, all_fields, &having); + if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ DBUG_RETURN(-1); From 13901802bcdc24094504e392b100a934174a11e3 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Mon, 18 Sep 2006 14:49:54 +0400 Subject: [PATCH 05/28] BUG#22393: Very wrong E(#rows(ref(const)) for key with skewed distribution - Check if we have E(#rows) for 'range' access on the smaller interval on the same index. If yes, adjust the estimate. --- mysql-test/r/range.result | 14 ++++++++++++++ mysql-test/t/range.test | 27 +++++++++++++++++++++++++++ sql/sql_select.cc | 23 +++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 776a86ad2d5..5335db5d78d 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -896,3 +896,17 @@ EXPLAIN SELECT * FROM t1 WHERE 0 NOT BETWEEN b AND c; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge idx1,idx2 idx1,idx2 4,4 NULL 4 Using sort_union(idx1,idx2); Using where DROP TABLE t1; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, filler char(100)); +insert into t2 select A.a + 10 * (B.a + 10 * C.a), 10, 'filler' from t1 A, +t1 B, t1 C where A.a < 5; +insert into t2 select 1000, b, 'filler' from t2; +alter table t2 add index (a,b); +select 'In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)' Z; +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; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 735d3f11359..bc260f71e6e 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -711,3 +711,30 @@ DROP TABLE t1; # End of 5.0 tests + +# BUG#22393 fix: Adjust 'ref' estimate if we have 'range' estimate for +# a smaller scan interval +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t2 (a int, b int, filler char(100)); +insert into t2 select A.a + 10 * (B.a + 10 * C.a), 10, 'filler' from t1 A, +t1 B, t1 C where A.a < 5; + +insert into t2 select 1000, b, 'filler' from t2; +alter table t2 add index (a,b); +# t2 values +# ( 1 , 10, 'filler') +# ( 2 , 10, 'filler') +# ( 3 , 10, 'filler') +# (... , 10, 'filler') +# ... +# (1000, 10, 'filler') - 500 times + +# 500 rows, 1 row + +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; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e048271ed3a..dc7c3840d4e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3711,7 +3711,30 @@ best_access_path(JOIN *join, { /* Check if we have statistic about the distribution */ if ((records= keyinfo->rec_per_key[max_key_part-1])) + { + /* + Fix for the case where the index statistics is too + optimistic: If + (1) We're considering ref(const) and there is quick select + on the same index, + (2) and that quick select uses more keyparts (i.e. it will + scan equal/smaller interval then this ref(const)) + (3) and E(#rows) for quick select is higher then our + estimate, + Then + We'll use E(#rows) from quick select. + + Q: Why do we choose to use 'ref'? Won't quick select be + cheaper in some cases ? + TODO: figure this out and adjust the plan choice if needed. + */ + if (!found_ref && table->quick_keys.is_set(key) && // (1) + table->quick_key_parts[key] > max_key_part && // (2) + records < (double)table->quick_rows[key]) // (3) + records= (double)table->quick_rows[key]; + tmp= records; + } else { /* From 0279c91d9971556d767c544ec7492d056ce2df64 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Tue, 19 Sep 2006 12:18:24 -0700 Subject: [PATCH 06/28] Post-merge corrections. --- mysql-test/r/ps.result | 98 ++++++++++++++++++------------------- mysql-test/t/ps.test | 108 ++++++++++++++++++++--------------------- 2 files changed, 103 insertions(+), 103 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 888ba5bdb5b..1727c4ddfbe 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -253,10 +253,10 @@ execute `ü` ; 1234 1234 set names latin1; -execute `ü`; +execute `ü`; 1234 1234 -deallocate prepare `ü`; +deallocate prepare `ü`; set names default; create table t1 (a varchar(10)) charset=utf8; insert into t1 (a) values ('yahoo'); @@ -820,53 +820,6 @@ ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should set local max_prepared_stmt_count=1; ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL set local prepared_stmt_count=0; -CREATE TABLE t1( -ID int(10) unsigned NOT NULL auto_increment, -Member_ID varchar(15) NOT NULL default '', -Action varchar(12) NOT NULL, -Action_Date datetime NOT NULL, -Track varchar(15) default NULL, -User varchar(12) default NULL, -Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update -CURRENT_TIMESTAMP, -PRIMARY KEY (ID), -KEY Action (Action), -KEY Action_Date (Action_Date) -); -INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES -('111111', 'Disenrolled', '2006-03-01', 'CAD' ), -('111111', 'Enrolled', '2006-03-01', 'CAD' ), -('111111', 'Disenrolled', '2006-07-03', 'CAD' ), -('222222', 'Enrolled', '2006-03-07', 'CAD' ), -('222222', 'Enrolled', '2006-03-07', 'CHF' ), -('222222', 'Disenrolled', '2006-08-02', 'CHF' ), -('333333', 'Enrolled', '2006-03-01', 'CAD' ), -('333333', 'Disenrolled', '2006-03-01', 'CAD' ), -('444444', 'Enrolled', '2006-03-01', 'CAD' ), -('555555', 'Disenrolled', '2006-03-01', 'CAD' ), -('555555', 'Enrolled', '2006-07-21', 'CAD' ), -('555555', 'Disenrolled', '2006-03-01', 'CHF' ), -('666666', 'Enrolled', '2006-02-09', 'CAD' ), -('666666', 'Enrolled', '2006-05-12', 'CHF' ), -('666666', 'Disenrolled', '2006-06-01', 'CAD' ); -PREPARE STMT FROM -"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 - WHERE Member_ID=? AND Action='Enrolled' AND - (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 - WHERE Member_ID=? - GROUP BY Track - HAVING Track>='CAD' AND - MAX(Action_Date)>'2006-03-01')"; -SET @id='111111'; -EXECUTE STMT USING @id,@id; -GROUP_CONCAT(Track SEPARATOR ', ') -NULL -SET @id='222222'; -EXECUTE STMT USING @id,@id; -GROUP_CONCAT(Track SEPARATOR ', ') -CAD -DEALLOCATE PREPARE STMT; -DROP TABLE t1; ERROR HY000: Variable 'prepared_stmt_count' is a read only variable set @@prepared_stmt_count=0; ERROR HY000: Variable 'prepared_stmt_count' is a read only variable @@ -956,6 +909,53 @@ create temporary table if not exists t1 (a1 int); execute stmt; drop temporary table t1; deallocate prepare stmt; +CREATE TABLE t1( +ID int(10) unsigned NOT NULL auto_increment, +Member_ID varchar(15) NOT NULL default '', +Action varchar(12) NOT NULL, +Action_Date datetime NOT NULL, +Track varchar(15) default NULL, +User varchar(12) default NULL, +Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update +CURRENT_TIMESTAMP, +PRIMARY KEY (ID), +KEY Action (Action), +KEY Action_Date (Action_Date) +); +INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES +('111111', 'Disenrolled', '2006-03-01', 'CAD' ), +('111111', 'Enrolled', '2006-03-01', 'CAD' ), +('111111', 'Disenrolled', '2006-07-03', 'CAD' ), +('222222', 'Enrolled', '2006-03-07', 'CAD' ), +('222222', 'Enrolled', '2006-03-07', 'CHF' ), +('222222', 'Disenrolled', '2006-08-02', 'CHF' ), +('333333', 'Enrolled', '2006-03-01', 'CAD' ), +('333333', 'Disenrolled', '2006-03-01', 'CAD' ), +('444444', 'Enrolled', '2006-03-01', 'CAD' ), +('555555', 'Disenrolled', '2006-03-01', 'CAD' ), +('555555', 'Enrolled', '2006-07-21', 'CAD' ), +('555555', 'Disenrolled', '2006-03-01', 'CHF' ), +('666666', 'Enrolled', '2006-02-09', 'CAD' ), +('666666', 'Enrolled', '2006-05-12', 'CHF' ), +('666666', 'Disenrolled', '2006-06-01', 'CAD' ); +PREPARE STMT FROM +"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 + WHERE Member_ID=? AND Action='Enrolled' AND + (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 + WHERE Member_ID=? + GROUP BY Track + HAVING Track>='CAD' AND + MAX(Action_Date)>'2006-03-01')"; +SET @id='111111'; +EXECUTE STMT USING @id,@id; +GROUP_CONCAT(Track SEPARATOR ', ') +NULL +SET @id='222222'; +EXECUTE STMT USING @id,@id; +GROUP_CONCAT(Track SEPARATOR ', ') +CAD +DEALLOCATE PREPARE STMT; +DROP TABLE t1; End of 4.1 tests create table t1 (a varchar(20)); insert into t1 values ('foo'); diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index ea9e98e1b1e..cc239306558 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -259,8 +259,8 @@ set names utf8; prepare `ü` from 'select 1234'; execute `ü` ; set names latin1; -execute `ü`; -deallocate prepare `ü`; +execute `ü`; +deallocate prepare `ü`; set names default; @@ -563,58 +563,6 @@ set @a=200887, @b=860; # this query did not return all matching rows execute stmt using @a, @b; deallocate prepare stmt; -# -# BUG#22085: Crash on the execution of a prepared statement that -# uses an IN subquery with aggregate functions in HAVING -# - -CREATE TABLE t1( - ID int(10) unsigned NOT NULL auto_increment, - Member_ID varchar(15) NOT NULL default '', - Action varchar(12) NOT NULL, - Action_Date datetime NOT NULL, - Track varchar(15) default NULL, - User varchar(12) default NULL, - Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update - CURRENT_TIMESTAMP, - PRIMARY KEY (ID), - KEY Action (Action), - KEY Action_Date (Action_Date) -); - -INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES - ('111111', 'Disenrolled', '2006-03-01', 'CAD' ), - ('111111', 'Enrolled', '2006-03-01', 'CAD' ), - ('111111', 'Disenrolled', '2006-07-03', 'CAD' ), - ('222222', 'Enrolled', '2006-03-07', 'CAD' ), - ('222222', 'Enrolled', '2006-03-07', 'CHF' ), - ('222222', 'Disenrolled', '2006-08-02', 'CHF' ), - ('333333', 'Enrolled', '2006-03-01', 'CAD' ), - ('333333', 'Disenrolled', '2006-03-01', 'CAD' ), - ('444444', 'Enrolled', '2006-03-01', 'CAD' ), - ('555555', 'Disenrolled', '2006-03-01', 'CAD' ), - ('555555', 'Enrolled', '2006-07-21', 'CAD' ), - ('555555', 'Disenrolled', '2006-03-01', 'CHF' ), - ('666666', 'Enrolled', '2006-02-09', 'CAD' ), - ('666666', 'Enrolled', '2006-05-12', 'CHF' ), - ('666666', 'Disenrolled', '2006-06-01', 'CAD' ); - -PREPARE STMT FROM -"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 - WHERE Member_ID=? AND Action='Enrolled' AND - (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 - WHERE Member_ID=? - GROUP BY Track - HAVING Track>='CAD' AND - MAX(Action_Date)>'2006-03-01')"; -SET @id='111111'; -EXECUTE STMT USING @id,@id; -SET @id='222222'; -EXECUTE STMT USING @id,@id; - -DEALLOCATE PREPARE STMT; -DROP TABLE t1; - drop table t1; @@ -1040,6 +988,58 @@ execute stmt; drop temporary table t1; deallocate prepare stmt; +# +# BUG#22085: Crash on the execution of a prepared statement that +# uses an IN subquery with aggregate functions in HAVING +# + +CREATE TABLE t1( + ID int(10) unsigned NOT NULL auto_increment, + Member_ID varchar(15) NOT NULL default '', + Action varchar(12) NOT NULL, + Action_Date datetime NOT NULL, + Track varchar(15) default NULL, + User varchar(12) default NULL, + Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update + CURRENT_TIMESTAMP, + PRIMARY KEY (ID), + KEY Action (Action), + KEY Action_Date (Action_Date) +); + +INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES + ('111111', 'Disenrolled', '2006-03-01', 'CAD' ), + ('111111', 'Enrolled', '2006-03-01', 'CAD' ), + ('111111', 'Disenrolled', '2006-07-03', 'CAD' ), + ('222222', 'Enrolled', '2006-03-07', 'CAD' ), + ('222222', 'Enrolled', '2006-03-07', 'CHF' ), + ('222222', 'Disenrolled', '2006-08-02', 'CHF' ), + ('333333', 'Enrolled', '2006-03-01', 'CAD' ), + ('333333', 'Disenrolled', '2006-03-01', 'CAD' ), + ('444444', 'Enrolled', '2006-03-01', 'CAD' ), + ('555555', 'Disenrolled', '2006-03-01', 'CAD' ), + ('555555', 'Enrolled', '2006-07-21', 'CAD' ), + ('555555', 'Disenrolled', '2006-03-01', 'CHF' ), + ('666666', 'Enrolled', '2006-02-09', 'CAD' ), + ('666666', 'Enrolled', '2006-05-12', 'CHF' ), + ('666666', 'Disenrolled', '2006-06-01', 'CAD' ); + +PREPARE STMT FROM +"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 + WHERE Member_ID=? AND Action='Enrolled' AND + (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 + WHERE Member_ID=? + GROUP BY Track + HAVING Track>='CAD' AND + MAX(Action_Date)>'2006-03-01')"; +SET @id='111111'; +EXECUTE STMT USING @id,@id; +SET @id='222222'; +EXECUTE STMT USING @id,@id; + +DEALLOCATE PREPARE STMT; +DROP TABLE t1; + --echo End of 4.1 tests ############################# 5.0 tests start ################################ # From 8577d7913e9c8d7a36a2b5593e9095bc36b2e514 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@rakia.(none)" <> Date: Wed, 20 Sep 2006 12:02:58 +0300 Subject: [PATCH 07/28] fixed merge --- mysql-test/r/func_group.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 32d6931c334..c6117053a60 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -860,8 +860,8 @@ CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1,1),(1,2),(2,3); SELECT (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a; (SELECT COUNT(DISTINCT t1.b)) -0 2 +1 SELECT (SELECT COUNT(DISTINCT 12)) FROM t1 GROUP BY t1.a; (SELECT COUNT(DISTINCT 12)) 1 From f2225cab27a2cfae4e18190159d95b9f6c5e10c7 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Wed, 20 Sep 2006 08:08:57 -0700 Subject: [PATCH 08/28] Fixed bug #22015: crash with GROUP_CONCAT over a derived table that returns the results of aggregation by GROUP_CONCAT. The crash was due to an overflow happened for the field sortoder->length. The fix prevents this overflow exploiting the fact that the value of sortoder->length cannot be greater than the value of thd->variables.max_sort_length. --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 15 +++++++++++++++ sql/filesort.cc | 1 + 3 files changed, 25 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 6617ccc671e..93925670d01 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -654,3 +654,12 @@ CHAR_LENGTH( GROUP_CONCAT(b) ) 240001 SET GROUP_CONCAT_MAX_LEN = 1024; DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,1), (1,2), (2,2), (1,3); +SELECT GROUP_CONCAT(a), x +FROM (SELECT a, GROUP_CONCAT(b) x FROM t1 GROUP BY a) AS s +GROUP BY x; +GROUP_CONCAT(a) x +2 1,2 +1 2,3 +DROP TABLE t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 98c21986aa9..b5c468e1638 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -447,3 +447,18 @@ SELECT a, CHAR_LENGTH(b) FROM t1; SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1; SET GROUP_CONCAT_MAX_LEN = 1024; DROP TABLE t1; + +# +# Bug #22015: crash with GROUP_CONCAT over a derived table that +# returns the results of aggregation by GROUP_CONCAT +# + +CREATE TABLE t1 (a int, b int); + +INSERT INTO t1 VALUES (2,1), (1,2), (2,2), (1,3); + +SELECT GROUP_CONCAT(a), x + FROM (SELECT a, GROUP_CONCAT(b) x FROM t1 GROUP BY a) AS s + GROUP BY x; + +DROP TABLE t1; diff --git a/sql/filesort.cc b/sql/filesort.cc index 42d25dbbaee..f13354d5c72 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1268,6 +1268,7 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, switch ((sortorder->result_type=sortorder->item->result_type())) { case STRING_RESULT: sortorder->length=sortorder->item->max_length; + set_if_smaller(sortorder->length, thd->variables.max_sort_length); if (use_strnxfrm((cs=sortorder->item->collation.collation))) { sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length); From d957636471fd05cc1af47d78ba199d253ae244b6 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Wed, 20 Sep 2006 09:46:12 -0700 Subject: [PATCH 09/28] Fixed bug #20108. Any default value for a enum fields over UCS2 charsets was corrupted when we put it into the frm file, as it had been overwritten by its HEX representation. To fix it now we save a copy of structure that represents the enum type and when putting the default values we use this copy. --- mysql-test/r/ctype_ucs.result | 21 +++++++++++++++++++ mysql-test/t/ctype_ucs.test | 21 +++++++++++++++++++ sql/field.h | 2 ++ sql/unireg.cc | 39 ++++++++++++++++++++++++++++------- 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 24a4ca9a85f..642a0fc13b5 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -747,6 +747,27 @@ select export_set(5, name, upper(name), ",", 5) from bug20536; export_set(5, name, upper(name), ",", 5) test1,TEST1,test1,TEST1,TEST1 'test\_2','TEST\_2','test\_2','TEST\_2','TEST\_2' +CREATE TABLE t1 ( +status enum('active','passive') collate latin1_general_ci +NOT NULL default 'passive' +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `status` enum('active','passive') character set latin1 collate latin1_general_ci NOT NULL default 'passive' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD a int NOT NULL AFTER status; +CREATE TABLE t2 ( +status enum('active','passive') collate ucs2_turkish_ci +NOT NULL default 'passive' +); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `status` enum('active','passive') character set ucs2 collate ucs2_turkish_ci NOT NULL default 'passive' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t2 ADD a int NOT NULL AFTER status; +DROP TABLE t1,t2; select password(name) from bug20536; password(name) ???????????????????? diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index d96b9938f1b..641080f48ab 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -482,6 +482,27 @@ select make_set(3, name, upper(name)) from bug20536; select export_set(5, name, upper(name)) from bug20536; select export_set(5, name, upper(name), ",", 5) from bug20536; +# +# Bug #20108: corrupted default enum value for a ucs2 field +# + +CREATE TABLE t1 ( + status enum('active','passive') collate latin1_general_ci + NOT NULL default 'passive' +); +SHOW CREATE TABLE t1; +ALTER TABLE t1 ADD a int NOT NULL AFTER status; + +CREATE TABLE t2 ( + status enum('active','passive') collate ucs2_turkish_ci + NOT NULL default 'passive' +); +SHOW CREATE TABLE t2; +ALTER TABLE t2 ADD a int NOT NULL AFTER status; + +DROP TABLE t1,t2; + + # Some broken functions: add these tests just to document current behavior. # PASSWORD and OLD_PASSWORD don't work with UCS2 strings, but to fix it would diff --git a/sql/field.h b/sql/field.h index a33cb0a93aa..79fb7ff76d1 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1192,6 +1192,8 @@ public: uint decimals,flags,pack_length; Field::utype unireg_check; TYPELIB *interval; // Which interval to use + TYPELIB *save_interval; // Temporary copy for the above + // Used only for UCS2 intervals List interval_list; CHARSET_INFO *charset; Field::geometry_type geom_type; diff --git a/sql/unireg.cc b/sql/unireg.cc index e3bf763f700..e4fdc77912c 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -190,13 +190,19 @@ bool mysql_create_frm(THD *thd, my_string file_name, goto err3; { - /* Unescape all UCS2 intervals: were escaped in pack_headers */ + /* + Restore all UCS2 intervals. + HEX representation of them is not needed anymore. + */ List_iterator it(create_fields); create_field *field; while ((field=it++)) { - if (field->interval && field->charset->mbminlen > 1) - unhex_type2(field->interval); + if (field->save_interval) + { + field->interval= field->save_interval; + field->save_interval= 0; + } } } DBUG_RETURN(0); @@ -452,18 +458,36 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, reclength=(uint) (field->offset+ data_offset + length); n_length+= (ulong) strlen(field->field_name)+1; field->interval_id=0; + field->save_interval= 0; if (field->interval) { uint old_int_count=int_count; if (field->charset->mbminlen > 1) { - /* Escape UCS2 intervals using HEX notation */ + /* + Escape UCS2 intervals using HEX notation to avoid + problems with delimiters between enum elements. + As the original representation is still needed in + the function make_empty_rec to create a record of + filled with default values it is saved in save_interval + The HEX representation is created from this copy. + */ + field->save_interval= field->interval; + field->interval= (TYPELIB*) sql_alloc(sizeof(TYPELIB)); + *field->interval= *field->save_interval; + field->interval->type_names= + (const char **) sql_alloc(sizeof(char*) * + (field->interval->count+1)); + field->interval->type_names[field->interval->count]= 0; + field->interval->type_lengths= + (uint *) sql_alloc(sizeof(uint) * field->interval->count); + for (uint pos= 0; pos < field->interval->count; pos++) { char *dst; - uint length= field->interval->type_lengths[pos], hex_length; - const char *src= field->interval->type_names[pos]; + uint length= field->save_interval->type_lengths[pos], hex_length; + const char *src= field->save_interval->type_names[pos]; const char *srcend= src + length; hex_length= length * 2; field->interval->type_lengths[pos]= hex_length; @@ -715,7 +739,8 @@ static bool make_empty_rec(File file,enum db_type table_type, field->charset, field->geom_type, field->unireg_check, - field->interval, + field->save_interval ? field->save_interval : + field->interval, field->field_name, &table); From 55dd569bab5dabd02c096cada8046ce4896894c4 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 25 Sep 2006 05:24:07 -0700 Subject: [PATCH 10/28] Fixed bug #21853: assert failure for a grouping query with an ALL/ANY quantified subquery in HAVING. The Item::split_sum_func2 method should not create Item_ref for objects of any class derived from Item_subselect. --- mysql-test/r/subselect.result | 36 ++++++++++++++++++++++++++++++++++ mysql-test/t/subselect.test | 37 +++++++++++++++++++++++++++++++++++ sql/item.cc | 1 + 3 files changed, 74 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index ba4de7f6406..ad847b5f156 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2946,3 +2946,39 @@ ORDER BY t2.c, t2.b LIMIT 1) WHERE t1.a = 10; a a b 10 1 359 drop table t1,t2; +CREATE TABLE t1 ( +field1 int NOT NULL, +field2 int NOT NULL, +field3 int NOT NULL, +PRIMARY KEY (field1,field2,field3) +); +CREATE TABLE t2 ( +fieldA int NOT NULL, +fieldB int NOT NULL, +PRIMARY KEY (fieldA,fieldB) +); +INSERT INTO t1 VALUES +(1,1,1), (1,1,2), (1,2,1), (1,2,2), (1,2,3), (1,3,1); +INSERT INTO t2 VALUES (1,1), (1,2), (1,3); +SELECT field1, field2, COUNT(*) +FROM t1 GROUP BY field1, field2; +field1 field2 COUNT(*) +1 1 2 +1 2 3 +1 3 1 +SELECT field1, field2 +FROM t1 +GROUP BY field1, field2 +HAVING COUNT(*) >= ALL (SELECT fieldB +FROM t2 WHERE fieldA = field1); +field1 field2 +1 2 +SELECT field1, field2 +FROM t1 +GROUP BY field1, field2 +HAVING COUNT(*) < ANY (SELECT fieldB +FROM t2 WHERE fieldA = field1); +field1 field2 +1 1 +1 3 +DROP TABLE t1, t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1018b5de005..6defa8b16a5 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1911,4 +1911,41 @@ SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r drop table t1,t2; +# +# Bug #21853: assert failure for a grouping query with +# an ALL/ANY quantified subquery in HAVING +# + +CREATE TABLE t1 ( + field1 int NOT NULL, + field2 int NOT NULL, + field3 int NOT NULL, + PRIMARY KEY (field1,field2,field3) +); +CREATE TABLE t2 ( + fieldA int NOT NULL, + fieldB int NOT NULL, + PRIMARY KEY (fieldA,fieldB) +); + +INSERT INTO t1 VALUES + (1,1,1), (1,1,2), (1,2,1), (1,2,2), (1,2,3), (1,3,1); +INSERT INTO t2 VALUES (1,1), (1,2), (1,3); + +SELECT field1, field2, COUNT(*) + FROM t1 GROUP BY field1, field2; + +SELECT field1, field2 + FROM t1 + GROUP BY field1, field2 + HAVING COUNT(*) >= ALL (SELECT fieldB + FROM t2 WHERE fieldA = field1); +SELECT field1, field2 + FROM t1 + GROUP BY field1, field2 + HAVING COUNT(*) < ANY (SELECT fieldB + FROM t2 WHERE fieldA = field1); + +DROP TABLE t1, t2; + # End of 4.1 tests diff --git a/sql/item.cc b/sql/item.cc index 7c9f6ec77fb..94f0a24fcc3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -387,6 +387,7 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, } else if ((type() == SUM_FUNC_ITEM || (used_tables() & ~PARAM_TABLE_BIT)) && + type() != SUBSELECT_ITEM && type() != REF_ITEM) { /* From a661bdda19264341c7d8cbf155e199e2e4bac383 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 25 Sep 2006 06:15:14 -0700 Subject: [PATCH 11/28] Fixed bug #21646. Presence of a subquery in the ON expression of a join should not block merging the view that contains this join. Before this patch the such views were converted into into temporary table views. --- mysql-test/r/view.result | 14 ++++++++++++++ mysql-test/t/view.test | 18 ++++++++++++++++++ sql/mysql_priv.h | 3 ++- sql/sql_lex.cc | 3 ++- sql/sql_yacc.yy | 8 ++++++++ 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 9c05aba168c..7b81072cfd7 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2935,4 +2935,18 @@ id select_type table type possible_keys key key_len ref rows Extra 2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1(pk int PRIMARY KEY); +CREATE TABLE t2(pk int PRIMARY KEY, fk int, ver int, org int); +CREATE ALGORITHM=MERGE VIEW v1 AS +SELECT t1.* +FROM t1 JOIN t2 +ON t2.fk = t1.pk AND +t2.ver = (SELECT MAX(t.ver) FROM t2 t WHERE t.org = t2.org); +SHOW WARNINGS; +Level Code Message +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`pk` AS `pk` from (`t1` join `t2` on(((`t2`.`fk` = `t1`.`pk`) and (`t2`.`ver` = (select max(`t`.`ver`) AS `MAX(t.ver)` from `t2` `t` where (`t`.`org` = `t2`.`org`)))))) +DROP VIEW v1; +DROP TABLE t1, t2; End of 5.0 tests. diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 4745804e847..b8cbb491832 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2850,4 +2850,22 @@ EXPLAIN SELECT * FROM v1 t WHERE t.s1+1 < (SELECT MAX(t1.s1) FROM t1); DROP VIEW v1; DROP TABLE t1; + +# +# Bug #21646: view qith a subquery in ON expression +# + +CREATE TABLE t1(pk int PRIMARY KEY); +CREATE TABLE t2(pk int PRIMARY KEY, fk int, ver int, org int); + +CREATE ALGORITHM=MERGE VIEW v1 AS +SELECT t1.* + FROM t1 JOIN t2 + ON t2.fk = t1.pk AND + t2.ver = (SELECT MAX(t.ver) FROM t2 t WHERE t.org = t2.org); +SHOW WARNINGS; +SHOW CREATE VIEW v1; + +DROP VIEW v1; +DROP TABLE t1, t2; --echo End of 5.0 tests. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f293c769d75..f011aa42437 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -446,7 +446,8 @@ enum enum_parsing_place NO_MATTER, IN_HAVING, SELECT_LIST, - IN_WHERE + IN_WHERE, + IN_ON }; struct st_table; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d0087b14d6a..788276ac654 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1710,7 +1710,8 @@ bool st_lex::can_be_merged() unit= unit->next_unit()) { if (unit->first_select()->parent_lex == this && - (unit->item == 0 || unit->item->place() != IN_WHERE)) + (unit->item == 0 || + (unit->item->place() != IN_WHERE && unit->item->place() != IN_ON))) { selects_allow_merge= 0; break; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e39deadbf12..d027af8941b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5212,11 +5212,13 @@ join_table: /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $3)) YYABORT; + Select->parsing_place= IN_ON; } expr { add_join_on($3,$6); Lex->pop_context(); + Select->parsing_place= NO_MATTER; } | table_ref STRAIGHT_JOIN table_factor ON @@ -5225,12 +5227,14 @@ join_table: /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $3)) YYABORT; + Select->parsing_place= IN_ON; } expr { $3->straight=1; add_join_on($3,$6); Lex->pop_context(); + Select->parsing_place= NO_MATTER; } | table_ref normal_join table_ref USING @@ -5254,6 +5258,7 @@ join_table: /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $5)) YYABORT; + Select->parsing_place= IN_ON; } expr { @@ -5261,6 +5266,7 @@ join_table: Lex->pop_context(); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; + Select->parsing_place= NO_MATTER; } | table_ref LEFT opt_outer JOIN_SYM table_factor { @@ -5285,6 +5291,7 @@ join_table: /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $5)) YYABORT; + Select->parsing_place= IN_ON; } expr { @@ -5293,6 +5300,7 @@ join_table: YYABORT; add_join_on($$, $8); Lex->pop_context(); + Select->parsing_place= NO_MATTER; } | table_ref RIGHT opt_outer JOIN_SYM table_factor { From 9fc769ff7246a3a88a56030fde3cb3acc325aff6 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Tue, 26 Sep 2006 20:52:54 +0400 Subject: [PATCH 12/28] Fixed bug #18360: Type aggregation for IN and CASE may lead to a wrong result The IN function aggregates result types of all expressions. It uses that type in comparison of left expression and expressions in right part. This approach works in most cases. But let's consider the case when the right part contains both strings and integers. In that case this approach may cause wrong results because all strings which do not start with a digit are evaluated as 0. CASE uses the same approach when a CASE expression is given thus it's also affected. The idea behind this fix is to make IN function to compare expressions with different result types differently. For example a string in the left part will be compared as string with strings specified in right part and will be converted to real for comparison to int or real items in the right part. A new function called collect_cmp_types() is added. It collects different result types for comparison of first item in the provided list with each other item in the list. The Item_func_in class now can refer up to 5 cmp_item objects: 1 for each result type for comparison purposes. cmp_item objects are allocated according to found result types. The comparison of the left expression with any right part expression is now based only on result types of these expressions. The Item_func_case class is modified in the similar way when a CASE expression is specified. Now it can allocate up to 5 cmp_item objects to compare CASE expression with WHEN expressions of different types. The comparison of the CASE expression with any WHEN expression now based only on result types of these expressions. --- mysql-test/r/func_in.result | 68 +++++++++ mysql-test/t/func_in.test | 24 +++ mysql-test/t/view.test | 2 +- sql/item.cc | 5 - sql/item_cmpfunc.cc | 296 ++++++++++++++++++++++-------------- sql/item_cmpfunc.h | 164 ++++++++++++++------ sql/opt_range.cc | 10 +- 7 files changed, 402 insertions(+), 167 deletions(-) diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 0236cbfe26f..b88e5a66f96 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -343,3 +343,71 @@ some_id 1 2 drop table t1; +create table t1(f1 char(1)); +insert into t1 values ('a'),('b'),('1'); +select f1 from t1 where f1 in ('a',1); +f1 +a +1 +select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; +f1 case f1 when 'a' then '+' when 1 then '-' end +a + +b NULL +1 - +create index t1f1_idx on t1(f1); +select f1 from t1 where f1 in ('a',1); +f1 +1 +a +explain select f1 from t1 where f1 in ('a',1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL t1f1_idx 2 NULL 3 Using where; Using index +select f1 from t1 where f1 in ('a','b'); +f1 +a +b +explain select f1 from t1 where f1 in ('a','b'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index +select f1 from t1 where f1 in (2,1); +f1 +1 +explain select f1 from t1 where f1 in (2,1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index +create table t2(f2 int, index t2f2(f2)); +insert into t2 values(0),(1),(2); +select f2 from t2 where f2 in ('a',2); +f2 +0 +2 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'a' +explain select f2 from t2 where f2 in ('a',2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index +select f2 from t2 where f2 in ('a','b'); +f2 +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'b' +explain select f2 from t2 where f2 in ('a','b'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'b' +select f2 from t2 where f2 in (1,'b'); +f2 +0 +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'b' +Warning 1292 Truncated incorrect DOUBLE value: 'b' +explain select f2 from t2 where f2 in (1,'b'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index +drop table t1, t2; diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 8ddf1fbe314..906747c2f78 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -232,3 +232,27 @@ select some_id from t1 where some_id not in(2,-1); select some_id from t1 where some_id not in(-4,-1,-4); select some_id from t1 where some_id not in(-4,-1,3423534,2342342); drop table t1; + +# +# Bug#18360: Type aggregation for IN and CASE may lead to a wrong result +# +create table t1(f1 char(1)); +insert into t1 values ('a'),('b'),('1'); +select f1 from t1 where f1 in ('a',1); +select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; +create index t1f1_idx on t1(f1); +select f1 from t1 where f1 in ('a',1); +explain select f1 from t1 where f1 in ('a',1); +select f1 from t1 where f1 in ('a','b'); +explain select f1 from t1 where f1 in ('a','b'); +select f1 from t1 where f1 in (2,1); +explain select f1 from t1 where f1 in (2,1); +create table t2(f2 int, index t2f2(f2)); +insert into t2 values(0),(1),(2); +select f2 from t2 where f2 in ('a',2); +explain select f2 from t2 where f2 in ('a',2); +select f2 from t2 where f2 in ('a','b'); +explain select f2 from t2 where f2 in ('a','b'); +select f2 from t2 where f2 in (1,'b'); +explain select f2 from t2 where f2 in (1,'b'); +drop table t1, t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 7d1ddccba83..e1291390b93 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2443,7 +2443,7 @@ DROP TABLE t1, t2; # # Bug #16069: VIEW does return the same results as underlying SELECT # with WHERE condition containing BETWEEN over dates - +# Dates as strings should be casted to date type CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, td date DEFAULT NULL, KEY idx(td)); diff --git a/sql/item.cc b/sql/item.cc index 62292a38245..f1c7a052988 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5704,11 +5704,6 @@ void Item_trigger_field::cleanup() } -/* - If item is a const function, calculate it and return a const item - The original item is freed if not returned -*/ - Item_result item_cmp_type(Item_result a,Item_result b) { if (a == STRING_RESULT && b == STRING_RESULT) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 0aa6d432966..135e4596996 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -66,12 +66,10 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) /* Aggregates result types from the array of items. - SYNOPSIS: + SYNOPSIS agg_cmp_type() - thd thread handle - type [out] the aggregated type - items array of items to aggregate the type from - nitems number of items in the array + items array of items to aggregate the type from + nitems number of items in the array DESCRIPTION This function aggregates result types from the array of items. Found type @@ -79,12 +77,43 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) Aggregation itself is performed by the item_cmp_type() function. */ -static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) +static Item_result agg_cmp_type(Item **items, uint nitems) { uint i; - type[0]= items[0]->result_type(); + Item_result type= items[0]->result_type(); for (i= 1 ; i < nitems ; i++) - type[0]= item_cmp_type(type[0], items[i]->result_type()); + type= item_cmp_type(type, items[i]->result_type()); + return type; +} + + +/* + Collects different types for comparison of first item with each other items + + SYNOPSIS + collect_cmp_types() + items Array of items to collect types from + nitems Number of items in the array + + DESCRIPTION + This function collects different result types for comparison of the first + item in the list with each of the remaining items in the 'items' array. + + RETURN + Bitmap of collected types +*/ + +static uint collect_cmp_types(Item **items, uint nitems) +{ + uint i; + uint found_types; + Item_result left_result= items[0]->result_type(); + DBUG_ASSERT(nitems > 1); + found_types= 0; + for (i= 1; i < nitems ; i++) + found_types|= 1<< (uint)item_cmp_type(left_result, + items[i]->result_type()); + return found_types; } @@ -1117,7 +1146,7 @@ void Item_func_between::fix_length_and_dec() */ if (!args[0] || !args[1] || !args[2]) return; - agg_cmp_type(thd, &cmp_type, args, 3); + cmp_type= agg_cmp_type(args, 3); if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1)) return; @@ -1597,94 +1626,65 @@ Item_func_nullif::is_null() return (null_value= (!cmp.compare() ? 1 : args[0]->null_value)); } + /* - CASE expression Return the matching ITEM or NULL if all compares (including else) failed + + SYNOPSIS + find_item() + str Buffer string + + DESCRIPTION + Find and return matching items for CASE or ELSE item if all compares + are failed or NULL if ELSE item isn't defined. + + IMPLEMENTATION + In order to do correct comparisons of the CASE expression (the expression + between CASE and the first WHEN) with each WHEN expression several + comparators are used. One for each result type. CASE expression can be + evaluated up to # of different result types are used. To check whether + the CASE expression already was evaluated for a particular result type + a bit mapped variable value_added_map is used. Result types are mapped + to it according to their int values i.e. STRING_RESULT is mapped to bit + 0, REAL_RESULT to bit 1, so on. + + RETURN + NULL - Nothing found and there is no ELSE expression defined + item - Found item or ELSE item if defined and all comparisons are + failed */ Item *Item_func_case::find_item(String *str) { - String *first_expr_str, *tmp; - my_decimal *first_expr_dec, first_expr_dec_val; - longlong first_expr_int; - double first_expr_real; - char buff[MAX_FIELD_WIDTH]; - String buff_str(buff,sizeof(buff),default_charset()); + uint value_added_map= 0; - /* These will be initialized later */ - LINT_INIT(first_expr_str); - LINT_INIT(first_expr_int); - LINT_INIT(first_expr_real); - LINT_INIT(first_expr_dec); - - if (first_expr_num != -1) + if (first_expr_num == -1) { - switch (cmp_type) - { - case STRING_RESULT: - // We can't use 'str' here as this may be overwritten - if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str))) - return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible - break; - case INT_RESULT: - first_expr_int= args[first_expr_num]->val_int(); - if (args[first_expr_num]->null_value) - return else_expr_num != -1 ? args[else_expr_num] : 0; - break; - case REAL_RESULT: - first_expr_real= args[first_expr_num]->val_real(); - if (args[first_expr_num]->null_value) - return else_expr_num != -1 ? args[else_expr_num] : 0; - break; - case DECIMAL_RESULT: - first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val); - if (args[first_expr_num]->null_value) - return else_expr_num != -1 ? args[else_expr_num] : 0; - break; - case ROW_RESULT: - default: - // This case should never be chosen - DBUG_ASSERT(0); - break; - } - } - - // Compare every WHEN argument with it and return the first match - for (uint i=0 ; i < ncases ; i+=2) - { - if (first_expr_num == -1) + for (uint i=0 ; i < ncases ; i+=2) { // No expression between CASE and the first WHEN if (args[i]->val_bool()) return args[i+1]; continue; } - switch (cmp_type) { - case STRING_RESULT: - if ((tmp=args[i]->val_str(str))) // If not null - if (sortcmp(tmp,first_expr_str,cmp_collation.collation)==0) - return args[i+1]; - break; - case INT_RESULT: - if (args[i]->val_int()==first_expr_int && !args[i]->null_value) - return args[i+1]; - break; - case REAL_RESULT: - if (args[i]->val_real() == first_expr_real && !args[i]->null_value) - return args[i+1]; - break; - case DECIMAL_RESULT: + } + else + { + /* Compare every WHEN argument with it and return the first match */ + for (uint i=0 ; i < ncases ; i+=2) { - my_decimal value; - if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0) - return args[i+1]; - break; - } - case ROW_RESULT: - default: - // This case should never be chosen - DBUG_ASSERT(0); - break; + cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); + DBUG_ASSERT(cmp_type != ROW_RESULT); + DBUG_ASSERT(cmp_items[(uint)cmp_type]); + if (!(value_added_map & (1<<(uint)cmp_type))) + { + cmp_items[(uint)cmp_type]->store_value(args[first_expr_num]); + if ((null_value=args[first_expr_num]->null_value)) + return else_expr_num != -1 ? args[else_expr_num] : 0; + value_added_map|= 1<<(uint)cmp_type; + } + if (!cmp_items[(uint)cmp_type]->cmp(args[i]) && !args[i]->null_value) + return args[i + 1]; } } // No, WHEN clauses all missed, return ELSE expression @@ -1791,7 +1791,7 @@ void Item_func_case::fix_length_and_dec() Item **agg; uint nagg; THD *thd= current_thd; - + uint found_types= 0; if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) return; @@ -1818,16 +1818,31 @@ void Item_func_case::fix_length_and_dec() */ if (first_expr_num != -1) { + uint i; agg[0]= args[first_expr_num]; + left_result_type= agg[0]->result_type(); + for (nagg= 0; nagg < ncases/2 ; nagg++) agg[nagg+1]= args[nagg*2]; nagg++; - agg_cmp_type(thd, &cmp_type, agg, nagg); - if ((cmp_type == STRING_RESULT) && - agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1)) - return; + found_types= collect_cmp_types(agg, nagg); + + for (i= 0; i <= (uint)DECIMAL_RESULT; i++) + { + if (found_types & (1 << i) && !cmp_items[i]) + { + DBUG_ASSERT((Item_result)i != ROW_RESULT); + if ((Item_result)i == STRING_RESULT && + agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1)) + return; + if (!(cmp_items[i]= + cmp_item::get_comparator((Item_result)i, + cmp_collation.collation))) + return; + } + } } - + if (else_expr_num == -1 || args[else_expr_num]->maybe_null) maybe_null=1; @@ -2412,16 +2427,14 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) void Item_func_in::fix_length_and_dec() { Item **arg, **arg_end; - uint const_itm= 1; + bool const_itm= 1; THD *thd= current_thd; + uint found_types= 0; + uint type_cnt= 0, i; + left_result_type= args[0]->result_type(); + found_types= collect_cmp_types(args, arg_count); - agg_cmp_type(thd, &cmp_type, args, arg_count); - - if (cmp_type == STRING_RESULT && - agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) - return; - - for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++) + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) { if (!arg[0]->const_item()) { @@ -2429,26 +2442,39 @@ void Item_func_in::fix_length_and_dec() break; } } - + for (i= 0; i <= (uint)DECIMAL_RESULT; i++) + { + if (found_types & 1 << i) + (type_cnt)++; + } /* - Row item with NULLs inside can return NULL or FALSE => + Row item with NULLs inside can return NULL or FALSE => they can't be processed as static */ - if (const_itm && !nulls_in_row()) + if (type_cnt == 1 && const_itm && !nulls_in_row()) { + uint tmp_type; + Item_result cmp_type; + /* Only one cmp type was found. Extract it here */ + for (tmp_type= 0; found_types - 1; found_types>>= 1) + tmp_type++; + cmp_type= (Item_result)tmp_type; + switch (cmp_type) { case STRING_RESULT: - array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in, + if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) + return; + array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in, cmp_collation.collation); break; case INT_RESULT: - array= new in_longlong(arg_count-1); + array= new in_longlong(arg_count - 1); break; case REAL_RESULT: - array= new in_double(arg_count-1); + array= new in_double(arg_count - 1); break; case ROW_RESULT: - array= new in_row(arg_count-1, args[0]); + array= new in_row(arg_count - 1, args[0]); break; case DECIMAL_RESULT: array= new in_decimal(arg_count - 1); @@ -2468,15 +2494,25 @@ void Item_func_in::fix_length_and_dec() else have_null= 1; } - if ((array->used_count=j)) + if ((array->used_count= j)) array->sort(); } } else { - in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation); - if (cmp_type == STRING_RESULT) - in_item->cmp_charset= cmp_collation.collation; + for (i= 0; i <= (uint) DECIMAL_RESULT; i++) + { + if (found_types & (1 << i) && !cmp_items[i]) + { + if ((Item_result)i == STRING_RESULT && + agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) + return; + if (!(cmp_items[i]= + cmp_item::get_comparator((Item_result)i, + cmp_collation.collation))) + return; + } + } } maybe_null= args[0]->maybe_null; max_length= 1; @@ -2495,25 +2531,61 @@ void Item_func_in::print(String *str) } +/* + Evaluate the function and return its value. + + SYNOPSIS + val_int() + + DESCRIPTION + Evaluate the function and return its value. + + IMPLEMENTATION + If the array object is defined then the value of the function is + calculated by means of this array. + Otherwise several cmp_item objects are used in order to do correct + comparison of left expression and an expression from the values list. + One cmp_item object correspond to one used comparison type. Left + expression can be evaluated up to number of different used comparison + types. A bit mapped variable value_added_map is used to check whether + the left expression already was evaluated for a particular result type. + Result types are mapped to it according to their integer values i.e. + STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on. + + RETURN + Value of the function +*/ + longlong Item_func_in::val_int() { + cmp_item *in_item; DBUG_ASSERT(fixed == 1); + uint value_added_map= 0; if (array) { int tmp=array->find(args[0]); null_value=args[0]->null_value || (!tmp && have_null); return (longlong) (!null_value && tmp != negated); } - in_item->store_value(args[0]); - if ((null_value=args[0]->null_value)) - return 0; - have_null= 0; - for (uint i=1 ; i < arg_count ; i++) + + for (uint i= 1 ; i < arg_count ; i++) { + Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); + in_item= cmp_items[(uint)cmp_type]; + DBUG_ASSERT(in_item); + if (!(value_added_map & (1 << (uint)cmp_type))) + { + in_item->store_value(args[0]); + if ((null_value=args[0]->null_value)) + return 0; + have_null= 0; + value_added_map|= 1 << (uint)cmp_type; + } if (!in_item->cmp(args[i]) && !args[i]->null_value) return (longlong) (!negated); have_null|= args[i]->null_value; } + null_value= have_null; return (longlong) (!null_value && negated); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a9149ade097..f2a8fd7db63 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -589,49 +589,6 @@ public: }; -class Item_func_case :public Item_func -{ - int first_expr_num, else_expr_num; - enum Item_result cached_result_type; - String tmp_value; - uint ncases; - Item_result cmp_type; - DTCollation cmp_collation; -public: - Item_func_case(List &list, Item *first_expr_arg, Item *else_expr_arg) - :Item_func(), first_expr_num(-1), else_expr_num(-1), - cached_result_type(INT_RESULT) - { - ncases= list.elements; - if (first_expr_arg) - { - first_expr_num= list.elements; - list.push_back(first_expr_arg); - } - if (else_expr_arg) - { - else_expr_num= list.elements; - list.push_back(else_expr_arg); - } - set_arguments(list); - } - double val_real(); - longlong val_int(); - String *val_str(String *); - my_decimal *val_decimal(my_decimal *); - bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); - uint decimal_precision() const; - table_map not_null_tables() const { return 0; } - enum Item_result result_type () const { return cached_result_type; } - const char *func_name() const { return "case"; } - void print(String *str); - Item *find_item(String *str); - CHARSET_INFO *compare_collation() { return cmp_collation.collation; } - bool check_partition_func_processor(byte *bool_arg) { return 0;} -}; - - /* Functions to handle the optimized IN */ @@ -686,6 +643,7 @@ public: { return test(compare(collation, base + pos1*size, base + pos2*size)); } + virtual Item_result result_type()= 0; }; class in_string :public in_vector @@ -707,6 +665,7 @@ public: Item_string *to= (Item_string*)item; to->str_value= *str; } + Item_result result_type() { return STRING_RESULT; } }; class in_longlong :public in_vector @@ -729,6 +688,7 @@ public: { ((Item_int*)item)->value= ((longlong*)base)[pos]; } + Item_result result_type() { return INT_RESULT; } }; class in_double :public in_vector @@ -746,6 +706,7 @@ public: { ((Item_float*)item)->value= ((double*) base)[pos]; } + Item_result result_type() { return REAL_RESULT; } }; @@ -766,6 +727,8 @@ public: Item_decimal *item_dec= (Item_decimal*)item; item_dec->set_decimal_value(dec); } + Item_result result_type() { return DECIMAL_RESULT; } + }; @@ -796,7 +759,9 @@ class cmp_item_string :public cmp_item protected: String *value_res; public: + cmp_item_string () {} cmp_item_string (CHARSET_INFO *cs) { cmp_charset= cs; } + void set_charset(CHARSET_INFO *cs) { cmp_charset= cs; } friend class cmp_item_sort_string; friend class cmp_item_sort_string_in_static; }; @@ -807,6 +772,8 @@ protected: char value_buff[STRING_BUFFER_USUAL_SIZE]; String value; public: + cmp_item_sort_string(): + cmp_item_string() {} cmp_item_sort_string(CHARSET_INFO *cs): cmp_item_string(cs), value(value_buff, sizeof(value_buff), cs) {} @@ -828,6 +795,11 @@ public: return sortcmp(value_res, cmp->value_res, cmp_charset); } cmp_item *make_same(); + void set_charset(CHARSET_INFO *cs) + { + cmp_charset= cs; + value.set_quick(value_buff, sizeof(value_buff), cs); + } }; class cmp_item_int :public cmp_item @@ -908,6 +880,7 @@ public: ~in_row(); void set(uint pos,Item *item); byte *get_value(Item *item); + Item_result result_type() { return ROW_RESULT; } }; /* @@ -943,18 +916,109 @@ public: } }; + +/* + The class Item_func_case is the CASE ... WHEN ... THEN ... END function + implementation. + + When there is no expression between CASE and the first WHEN + (the CASE expression) then this function simple checks all WHEN expressions + one after another. When some WHEN expression evaluated to TRUE then the + value of the corresponding THEN expression is returned. + + When the CASE expression is specified then it is compared to each WHEN + expression individually. When an equal WHEN expression is found + corresponding THEN expression is returned. + In order to do correct comparisons several comparators are used. One for + each result type. Different result types that are used in particular + CASE ... END expression are collected in the fix_length_and_dec() member + function and only comparators for there result types are used. +*/ + +class Item_func_case :public Item_func +{ + int first_expr_num, else_expr_num; + enum Item_result cached_result_type, left_result_type; + String tmp_value; + uint ncases; + Item_result cmp_type; + DTCollation cmp_collation; + cmp_item *cmp_items[5]; /* For all result types */ + cmp_item *case_item; +public: + Item_func_case(List &list, Item *first_expr_arg, Item *else_expr_arg) + :Item_func(), first_expr_num(-1), else_expr_num(-1), + cached_result_type(INT_RESULT), left_result_type(INT_RESULT), case_item(0) + { + ncases= list.elements; + if (first_expr_arg) + { + first_expr_num= list.elements; + list.push_back(first_expr_arg); + } + if (else_expr_arg) + { + else_expr_num= list.elements; + list.push_back(else_expr_arg); + } + set_arguments(list); + bzero(&cmp_items, sizeof(cmp_items)); + } + double val_real(); + longlong val_int(); + String *val_str(String *); + my_decimal *val_decimal(my_decimal *); + bool fix_fields(THD *thd, Item **ref); + void fix_length_and_dec(); + uint decimal_precision() const; + table_map not_null_tables() const { return 0; } + enum Item_result result_type () const { return cached_result_type; } + const char *func_name() const { return "case"; } + void print(String *str); + Item *find_item(String *str); + CHARSET_INFO *compare_collation() { return cmp_collation.collation; } + bool check_partition_func_processor(byte *bool_arg) { return 0;} + void cleanup() + { + uint i; + DBUG_ENTER("Item_func_case::cleanup"); + Item_func::cleanup(); + for (i= 0; i <= (uint)DECIMAL_RESULT; i++) + { + delete cmp_items[i]; + cmp_items[i]= 0; + } + DBUG_VOID_RETURN; + } +}; + +/* + The Item_func_in class implements the in_expr IN(values_list) function. + + The current implementation distinguishes 2 cases: + 1) all items in the value_list are constants and have the same + result type. This case is handled by in_vector class. + 2) items in the value_list have different result types or there is some + non-constant items. + In this case Item_func_in employs several cmp_item objects to performs + comparisons of in_expr and an item from the values_list. One cmp_item + object for each result type. Different result types are collected in the + fix_length_and_dec() member function by means of collect_cmp_types() + function. +*/ class Item_func_in :public Item_func_opt_neg { public: - Item_result cmp_type; in_vector *array; - cmp_item *in_item; bool have_null; + Item_result left_result_type; + cmp_item *cmp_items[5]; /* One cmp_item for each result type */ DTCollation cmp_collation; Item_func_in(List &list) - :Item_func_opt_neg(list), array(0), in_item(0), have_null(0) + :Item_func_opt_neg(list), array(0), have_null(0) { + bzero(&cmp_items, sizeof(cmp_items)); allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); @@ -963,12 +1027,16 @@ public: uint decimal_precision() const { return 1; } void cleanup() { + uint i; DBUG_ENTER("Item_func_in::cleanup"); Item_int_func::cleanup(); delete array; - delete in_item; array= 0; - in_item= 0; + for (i= 0; i <= (uint)DECIMAL_RESULT; i++) + { + delete cmp_items[i]; + cmp_items[i]= 0; + } DBUG_VOID_RETURN; } optimize_type select_optimize() const diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 13ffed4293e..fcdae26d98f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -4917,9 +4917,17 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, { Item_func_in *func=(Item_func_in*) cond_func; + /* + Array for IN() is constructed when all values have the same result + type. Tree won't be built for values with different result types, + so we check it here to avoid unnecessary work. + */ + if (!func->array) + break; + if (inv) { - if (func->array && func->cmp_type != ROW_RESULT) + if (func->array->result_type() != ROW_RESULT) { /* We get here for conditions in form "t.key NOT IN (c1, c2, ...)", From f9a02811da32522d3aa8c7c83b094d35f8515e3e Mon Sep 17 00:00:00 2001 From: "brian@zim.(none)" <> Date: Tue, 26 Sep 2006 21:26:04 -0700 Subject: [PATCH 13/28] Removed Field (this came in as an idea from a previous patch by Serg) --- include/mysql/plugin.h | 1 - sql/ha_ndbcluster.cc | 2 +- sql/ha_partition.cc | 2 +- sql/log.cc | 2 +- storage/archive/ha_archive.cc | 2 +- storage/blackhole/ha_blackhole.cc | 2 +- storage/csv/ha_tina.cc | 2 +- storage/example/ha_example.cc | 2 +- storage/federated/ha_federated.cc | 2 +- storage/heap/ha_heap.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 2 +- storage/myisam/ha_myisam.cc | 2 +- storage/myisammrg/ha_myisammrg.cc | 2 +- 13 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index ae952ccab1e..174c2b85739 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -301,7 +301,6 @@ struct st_mysql_ftparser struct st_mysql_storage_engine { int interface_version; - struct handlerton *handlerton; }; #endif diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0739b704462..157af825063 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -10749,7 +10749,7 @@ SHOW_VAR ndb_status_variables_export[]= { }; struct st_mysql_storage_engine ndbcluster_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, ndbcluster_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(ndbcluster) { diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e435b356def..8e704f34550 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5632,7 +5632,7 @@ static int free_share(PARTITION_SHARE *share) #endif /* NOT_USED */ struct st_mysql_storage_engine partition_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, partition_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(partition) { diff --git a/sql/log.cc b/sql/log.cc index 37f145bbecd..ec13cd89b92 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4681,7 +4681,7 @@ err1: } struct st_mysql_storage_engine binlog_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, binlog_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(binlog) { diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index c31bbfd612e..3971c4d73f0 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1571,7 +1571,7 @@ bool ha_archive::check_and_repair(THD *thd) } struct st_mysql_storage_engine archive_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, archive_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(archive) { diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc index bef5ee656fe..2ebe43acd4d 100644 --- a/storage/blackhole/ha_blackhole.cc +++ b/storage/blackhole/ha_blackhole.cc @@ -212,7 +212,7 @@ static int blackhole_init(void *p) } struct st_mysql_storage_engine blackhole_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, blackhole_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(blackhole) { diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 012e9b9bd7f..8007ebfecd1 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -1516,7 +1516,7 @@ bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info, } struct st_mysql_storage_engine csv_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, tina_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(csv) { diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index c4c2524a118..1b49cbbae5a 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -703,7 +703,7 @@ int ha_example::create(const char *name, TABLE *table_arg, } struct st_mysql_storage_engine example_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, example_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(example) diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 3bb34e5aacc..ecfaa9dff2d 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -2882,7 +2882,7 @@ int ha_federated::execute_simple_query(const char *query, int len) } struct st_mysql_storage_engine federated_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, federated_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(federated) { diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index d550442b0ec..1b76b24bd5d 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -701,7 +701,7 @@ bool ha_heap::check_if_incompatible_data(HA_CREATE_INFO *info, } struct st_mysql_storage_engine heap_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, heap_hton}; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(heap) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 84533d6c814..8fa04246769 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7607,7 +7607,7 @@ SHOW_VAR innodb_status_variables_export[]= { }; struct st_mysql_storage_engine innobase_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, innobase_hton}; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(innobase) { diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 28955bf9061..da4b4307f21 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1801,7 +1801,7 @@ static int myisam_init(void *p) } struct st_mysql_storage_engine myisam_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, myisam_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(myisam) { diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 6ed07df1012..bc756e78023 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -568,7 +568,7 @@ static int myisammrg_init(void *p) } struct st_mysql_storage_engine myisammrg_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION, myisammrg_hton }; +{ MYSQL_HANDLERTON_INTERFACE_VERSION }; mysql_declare_plugin(myisammrg) { From 903387afc00fbc367aefbc32f973ea3b52d85fd9 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Wed, 27 Sep 2006 12:53:53 +0300 Subject: [PATCH 14/28] Bug #21174: Index degrades sort performance and optimizer does not honor IGNORE INDEX - reversed the patch for 5.0 and moved to 5.1 --- mysql-test/r/group_by.result | 9 --------- mysql-test/t/group_by.test | 12 ------------ sql/sql_select.cc | 2 -- 3 files changed, 23 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index ef057e04d1a..5eb2e5744c1 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -821,12 +821,3 @@ a b real_b 68 France France DROP VIEW v1; DROP TABLE t1,t2; -CREATE TABLE t1 (a INT, b INT, KEY(a)); -INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); -EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 5 NULL 4 -EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort -DROP TABLE t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 8a514108dc3..ce1e4e59600 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -655,15 +655,3 @@ where t2.b=v1.a GROUP BY t2.b; DROP VIEW v1; DROP TABLE t1,t2; - -# -# Bug #21174: Index degrades sort performance and -# optimizer does not honor IGNORE INDEX -# -CREATE TABLE t1 (a INT, b INT, KEY(a)); -INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); - -EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; -EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; - -DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c38a9f4e637..d43f9fa214f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11735,8 +11735,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, We must not try to use disabled keys. */ usable_keys= table->s->keys_in_use; - /* we must not consider keys that are disabled by IGNORE INDEX */ - usable_keys.intersect(table->keys_in_use_for_query); for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { From 24c5bf6a96a4efa5bec1f057fea98ab98105ef9e Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Wed, 27 Sep 2006 13:11:00 +0300 Subject: [PATCH 15/28] Bug#21174: Index degrades sort performance and optimizer does not honor IGNORE INDEX - fix moved to 5.1 --- mysql-test/r/group_by.result | 9 +++++++++ mysql-test/t/group_by.test | 12 ++++++++++++ sql/sql_select.cc | 2 ++ 3 files changed, 23 insertions(+) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 7e8531bff58..80988bd8047 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -821,3 +821,12 @@ a b real_b 68 France France DROP VIEW v1; DROP TABLE t1,t2; +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); +EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 4 +EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +DROP TABLE t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index ce1e4e59600..8a514108dc3 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -655,3 +655,15 @@ where t2.b=v1.a GROUP BY t2.b; DROP VIEW v1; DROP TABLE t1,t2; + +# +# Bug #21174: Index degrades sort performance and +# optimizer does not honor IGNORE INDEX +# +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); + +EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; +EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; + +DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f247bfe7b14..9a05aa7da04 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11875,6 +11875,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, We must not try to use disabled keys. */ usable_keys= table->s->keys_in_use; + /* we must not consider keys that are disabled by IGNORE INDEX */ + usable_keys.intersect(table->keys_in_use_for_query); for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { From 4dcac0ff19e72b1f39a6d11c196504438472b2ff Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Wed, 27 Sep 2006 17:49:51 +0300 Subject: [PATCH 16/28] merge fixes 5.0-opt -> 5.1-opt --- mysql-test/r/ctype_ucs.result | 4 ++-- sql/unireg.cc | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 79aedc2ceed..4f08b97492f 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -762,7 +762,7 @@ NOT NULL default 'passive' SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `status` enum('active','passive') character set latin1 collate latin1_general_ci NOT NULL default 'passive' + `status` enum('active','passive') CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL DEFAULT 'passive' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ALTER TABLE t1 ADD a int NOT NULL AFTER status; CREATE TABLE t2 ( @@ -772,7 +772,7 @@ NOT NULL default 'passive' SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( - `status` enum('active','passive') character set ucs2 collate ucs2_turkish_ci NOT NULL default 'passive' + `status` enum('active','passive') CHARACTER SET ucs2 COLLATE ucs2_turkish_ci NOT NULL DEFAULT 'passive' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ALTER TABLE t2 ADD a int NOT NULL AFTER status; DROP TABLE t1,t2; diff --git a/sql/unireg.cc b/sql/unireg.cc index 11d974e644e..10e21654939 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -866,7 +866,8 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type, /* regfield don't have to be deleted as it's allocated with sql_alloc() */ - Field *regfield=make_field((char*) buff+field->offset + data_offset, + Field *regfield=make_field(&share, + (char*) buff+field->offset + data_offset, field->length, null_pos + null_count / 8, null_count & 7, From 041dedfcfb063982b9292fa9f7dd7dd6de3576e8 Mon Sep 17 00:00:00 2001 From: "gbichot@dl145h.mysql.com" <> Date: Thu, 28 Sep 2006 13:19:43 +0200 Subject: [PATCH 17/28] In the handlerton, cursor creation function don't have an argument and so the engine calls current_thd to derive transaction information; instead we now pass THD to those functions, it looks more logical (it makes the implicit current_thd parameter more visible). Approved by Brian and Monty. --- sql/handler.h | 6 +++--- sql/sql_cursor.cc | 8 ++++---- storage/innobase/handler/ha_innodb.cc | 12 ++++++++---- storage/innobase/handler/ha_innodb.h | 11 ++++++++--- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index 21ddb2c97d9..250d120c533 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -630,9 +630,9 @@ struct handlerton int (*recover)(XID *xid_list, uint len); int (*commit_by_xid)(XID *xid); int (*rollback_by_xid)(XID *xid); - void *(*create_cursor_read_view)(); - void (*set_cursor_read_view)(void *); - void (*close_cursor_read_view)(void *); + void *(*create_cursor_read_view)(THD *thd); + void (*set_cursor_read_view)(THD *thd, void *read_view); + void (*close_cursor_read_view)(THD *thd, void *read_view); handler *(*create)(TABLE_SHARE *table, MEM_ROOT *mem_root); void (*drop_database)(char* path); int (*panic)(enum ha_panic_function flag); diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 2784e71ccae..82ee8d72d33 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -323,7 +323,7 @@ Sensitive_cursor::post_open(THD *thd) if (ht->create_cursor_read_view) { info->ht= ht; - info->read_view= (ht->create_cursor_read_view)(); + info->read_view= (ht->create_cursor_read_view)(thd); ++info; } } @@ -433,7 +433,7 @@ Sensitive_cursor::fetch(ulong num_rows) thd->set_n_backup_active_arena(this, &backup_arena); for (info= ht_info; info->read_view ; info++) - (info->ht->set_cursor_read_view)(info->read_view); + (info->ht->set_cursor_read_view)(thd, info->read_view); join->fetch_limit+= num_rows; @@ -454,7 +454,7 @@ Sensitive_cursor::fetch(ulong num_rows) reset_thd(thd); for (info= ht_info; info->read_view; info++) - (info->ht->set_cursor_read_view)(0); + (info->ht->set_cursor_read_view)(thd, 0); if (error == NESTED_LOOP_CURSOR_LIMIT) { @@ -487,7 +487,7 @@ Sensitive_cursor::close() for (Engine_info *info= ht_info; info->read_view; info++) { - (info->ht->close_cursor_read_view)(info->read_view); + (info->ht->close_cursor_read_view)(thd, info->read_view); info->read_view= 0; info->ht= 0; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 84533d6c814..004586dd5aa 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7529,12 +7529,14 @@ This consistent view is then used inside of MySQL when accessing records using a cursor. */ void* -innobase_create_cursor_view(void) -/*=============================*/ - /* out: Pointer to cursor view or NULL */ +innobase_create_cursor_view( +/*========================*/ + /* out: pointer to cursor + view or NULL */ + THD* thd) /* in: user thread handle */ { return(read_cursor_view_create_for_mysql( - check_trx_exists(current_thd))); + check_trx_exists(thd))); } /*********************************************************************** @@ -7545,6 +7547,7 @@ corresponding MySQL thread still lacks one. */ void innobase_close_cursor_view( /*=======================*/ + THD* thd, /* in: user thread handle */ void* curview)/* in: Consistent read view to be closed */ { read_cursor_view_close_for_mysql(check_trx_exists(current_thd), @@ -7560,6 +7563,7 @@ restored to a transaction read view. */ void innobase_set_cursor_view( /*=====================*/ + THD* thd, /* in: user thread handle */ void* curview)/* in: Consistent cursor view to be set */ { read_cursor_set_for_mysql(check_trx_exists(current_thd), diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 4d5dc6b52d6..ed52ee9b094 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -313,9 +313,11 @@ This consistent view is then used inside of MySQL when accessing records using a cursor. */ void* -innobase_create_cursor_view(void); -/*=============================*/ - /* out: Pointer to cursor view or NULL */ +innobase_create_cursor_view( +/*========================*/ + /* out: pointer to cursor + view or NULL */ + THD* thd); /* in: user thread handle */ /*********************************************************************** Close the given consistent cursor view of a transaction and restore @@ -325,8 +327,10 @@ corresponding MySQL thread still lacks one. */ void innobase_close_cursor_view( /*=======================*/ + THD* thd, /* in: user thread handle */ void* curview); /* in: Consistent read view to be closed */ + /*********************************************************************** Set the given consistent cursor view to a transaction which is created if the corresponding MySQL thread still lacks one. If the given @@ -336,4 +340,5 @@ restored to a transaction read view. */ void innobase_set_cursor_view( /*=====================*/ + THD* thd, /* in: user thread handle */ void* curview); /* in: Consistent read view to be set */ From f6fbbf20022806528cbc25eef03febe613984d28 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Fri, 29 Sep 2006 01:00:18 +0400 Subject: [PATCH 18/28] Fixed bug#5505: Wrong error message on INSERT into a view On an INSERT into an updatable but non-insertable view an error message was issued stating the view being not updatable. This can lead to a confusion of a user. A new error message is introduced. Is is showed when a user tries to insert into a non-insertable view. --- mysql-test/r/view.result | 27 +++++++++++++++++---------- mysql-test/t/view.test | 32 ++++++++++++++++++++++---------- sql/share/errmsg.txt | 3 +++ sql/sql_base.cc | 5 ++++- sql/sql_insert.cc | 4 ++-- sql/sql_view.cc | 2 +- 6 files changed, 49 insertions(+), 24 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 9c05aba168c..262ed48a0c4 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -472,11 +472,11 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; insert into v3 values (-60,4,30); -ERROR HY000: The target table v3 of the INSERT is not updatable +ERROR HY000: The target table v3 of the INSERT is not insertable-into insert into v4 values (-60,4,30); -ERROR HY000: The target table v4 of the INSERT is not updatable +ERROR HY000: The target table v4 of the INSERT is not insertable-into insert into v5 values (-60,4,30); -ERROR HY000: The target table v5 of the INSERT is not updatable +ERROR HY000: The target table v5 of the INSERT is not insertable-into insert into v1 values (-60,4,30); insert into v1 (z,y,x) values (50,6,-100); insert into v2 values (5,40); @@ -499,11 +499,11 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; insert into v3 select c, b, a from t2; -ERROR HY000: The target table v3 of the INSERT is not updatable +ERROR HY000: The target table v3 of the INSERT is not insertable-into insert into v4 select c, b, a from t2; -ERROR HY000: The target table v4 of the INSERT is not updatable +ERROR HY000: The target table v4 of the INSERT is not insertable-into insert into v5 select c, b, a from t2; -ERROR HY000: The target table v5 of the INSERT is not updatable +ERROR HY000: The target table v5 of the INSERT is not insertable-into insert into v1 select c, b, a from t2; insert into v1 (z,y,x) select a+20,b+2,-100 from t2; insert into v2 select b+1, a+10 from t2; @@ -1352,14 +1352,14 @@ drop table t1; create table t1 (s1 smallint); create view v1 as select * from t1 where 20 < (select (s1) from t1); insert into v1 values (30); -ERROR HY000: The target table v1 of the INSERT is not updatable +ERROR HY000: The target table v1 of the INSERT is not insertable-into create view v2 as select * from t1; create view v3 as select * from t1 where 20 < (select (s1) from v2); insert into v3 values (30); -ERROR HY000: The target table v3 of the INSERT is not updatable +ERROR HY000: The target table v3 of the INSERT is not insertable-into create view v4 as select * from v2 where 20 < (select (s1) from t1); insert into v4 values (30); -ERROR HY000: The target table v4 of the INSERT is not updatable +ERROR HY000: The target table v4 of the INSERT is not insertable-into drop view v4, v3, v2, v1; drop table t1; create table t1 (a int); @@ -2911,7 +2911,7 @@ INSERT INTO v2 VALUES (0); RETURN 0; END | SELECT f2(); -ERROR HY000: The target table v2 of the INSERT is not updatable +ERROR HY000: The target table v2 of the INSERT is not insertable-into DROP FUNCTION f1; DROP FUNCTION f2; DROP VIEW v1, v2; @@ -2935,4 +2935,11 @@ id select_type table type possible_keys key key_len ref rows Extra 2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 DROP VIEW v1; DROP TABLE t1; +create table t1 (s1 int); +create view v1 as select s1 as a, s1 as b from t1; +insert into v1 values (1,1); +ERROR HY000: The target table v1 of the INSERT is not insertable-into +update v1 set a = 5; +drop view v1; +drop table t1; End of 5.0 tests. diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 4745804e847..1a022cdbf66 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -347,13 +347,13 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; # try insert to VIEW with fields duplicate --- error 1288 +-- error 1470 insert into v3 values (-60,4,30); # try insert to VIEW with expression in SELECT list --- error 1288 +-- error 1470 insert into v4 values (-60,4,30); # try insert to VIEW using temporary table algorithm --- error 1288 +-- error 1470 insert into v5 values (-60,4,30); insert into v1 values (-60,4,30); insert into v1 (z,y,x) values (50,6,-100); @@ -375,13 +375,13 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; # try insert to VIEW with fields duplicate --- error 1288 +-- error 1470 insert into v3 select c, b, a from t2; # try insert to VIEW with expression in SELECT list --- error 1288 +-- error 1470 insert into v4 select c, b, a from t2; # try insert to VIEW using temporary table algorithm --- error 1288 +-- error 1470 insert into v5 select c, b, a from t2; insert into v1 select c, b, a from t2; insert into v1 (z,y,x) select a+20,b+2,-100 from t2; @@ -1249,14 +1249,14 @@ drop table t1; # create table t1 (s1 smallint); create view v1 as select * from t1 where 20 < (select (s1) from t1); --- error 1288 +-- error 1470 insert into v1 values (30); create view v2 as select * from t1; create view v3 as select * from t1 where 20 < (select (s1) from v2); --- error 1288 +-- error 1470 insert into v3 values (30); create view v4 as select * from v2 where 20 < (select (s1) from t1); --- error 1288 +-- error 1470 insert into v4 values (30); drop view v4, v3, v2, v1; drop table t1; @@ -2825,7 +2825,7 @@ BEGIN END | delimiter ;| ---error ER_NON_UPDATABLE_TABLE +--error ER_NON_INSERTABLE_TABLE SELECT f2(); DROP FUNCTION f1; @@ -2850,4 +2850,16 @@ EXPLAIN SELECT * FROM v1 t WHERE t.s1+1 < (SELECT MAX(t1.s1) FROM t1); DROP VIEW v1; DROP TABLE t1; + +# +# Bug #5505: Wrong error message on INSERT into a view +# +create table t1 (s1 int); +create view v1 as select s1 as a, s1 as b from t1; +--error 1470 +insert into v1 values (1,1); +update v1 set a = 5; +drop view v1; +drop table t1; + --echo End of 5.0 tests. diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index d10f66e3878..151e73460ba 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5629,3 +5629,6 @@ ER_HOSTNAME eng "host name" ER_WRONG_STRING_LENGTH eng "String '%-.70s' is too long for %s (should be no longer than %d)" +ER_NON_INSERTABLE_TABLE + eng "The target table %-.100s of the %s is not insertable-into" + diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c29c610b200..85be84d1270 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -902,8 +902,11 @@ void update_non_unique_table_error(TABLE_LIST *update, */ if (update->view) { + /* Issue the ER_NON_INSERTABLE_TABLE error for an INSERT */ if (update->view == duplicate->view) - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), update->alias, operation); + my_error(!strncmp(operation, "INSERT", 6) ? + ER_NON_INSERTABLE_TABLE : ER_NON_UPDATABLE_TABLE, MYF(0), + update->alias, operation); else my_error(ER_VIEW_PREVENT_UPDATE, MYF(0), (duplicate->view ? duplicate->alias : update->alias), diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b5dab814d08..3db6eae8695 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -111,7 +111,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (!table_list->updatable) { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); + my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; } @@ -214,7 +214,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, (table_list->view && check_view_insertability(thd, table_list))) { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); + my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 4e2b48d9faf..94c5ad331dd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1574,7 +1574,7 @@ bool insert_view_fields(THD *thd, List *list, TABLE_LIST *view) list->push_back(fld); else { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT"); + my_error(ER_NON_INSERTABLE_TABLE, MYF(0), view->alias, "INSERT"); DBUG_RETURN(TRUE); } } From dead2e0f147017e85e4934fb65103adc464041ec Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Fri, 29 Sep 2006 01:35:11 +0400 Subject: [PATCH 19/28] view.test: After merge fix --- mysql-test/t/view.test | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index c732a019048..b631d2032c4 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -347,13 +347,13 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; # try insert to VIEW with fields duplicate --- error 1470 +-- error 1471 insert into v3 values (-60,4,30); # try insert to VIEW with expression in SELECT list --- error 1470 +-- error 1471 insert into v4 values (-60,4,30); # try insert to VIEW using temporary table algorithm --- error 1470 +-- error 1471 insert into v5 values (-60,4,30); insert into v1 values (-60,4,30); insert into v1 (z,y,x) values (50,6,-100); @@ -375,13 +375,13 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; # try insert to VIEW with fields duplicate --- error 1470 +-- error 1471 insert into v3 select c, b, a from t2; # try insert to VIEW with expression in SELECT list --- error 1470 +-- error 1471 insert into v4 select c, b, a from t2; # try insert to VIEW using temporary table algorithm --- error 1470 +-- error 1471 insert into v5 select c, b, a from t2; insert into v1 select c, b, a from t2; insert into v1 (z,y,x) select a+20,b+2,-100 from t2; @@ -1249,14 +1249,14 @@ drop table t1; # create table t1 (s1 smallint); create view v1 as select * from t1 where 20 < (select (s1) from t1); --- error 1470 +-- error 1471 insert into v1 values (30); create view v2 as select * from t1; create view v3 as select * from t1 where 20 < (select (s1) from v2); --- error 1470 +-- error 1471 insert into v3 values (30); create view v4 as select * from v2 where 20 < (select (s1) from t1); --- error 1470 +-- error 1471 insert into v4 values (30); drop view v4, v3, v2, v1; drop table t1; @@ -2856,7 +2856,7 @@ DROP TABLE t1; # create table t1 (s1 int); create view v1 as select s1 as a, s1 as b from t1; ---error 1470 +--error 1471 insert into v1 values (1,1); update v1 set a = 5; drop view v1; From 47b357522a2e9329b2c0376db0199508fe3654d8 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Fri, 29 Sep 2006 15:58:47 +0400 Subject: [PATCH 20/28] BUG#14940: Slow join order is chosen: [2nd commit with post-review fixes] - Re-worked the prev_record_reads() function to return the lower bound of number of different table access scans that will be performed. --- mysql-test/r/join.result | 28 ++++++++++ mysql-test/t/join.test | 21 ++++++++ sql/sql_select.cc | 111 ++++++++++++++++++++++++++++++++++----- sql/sql_select.h | 14 +++++ 4 files changed, 161 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 75daa0fd46d..897ec4f7a6a 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -776,3 +776,31 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL a,b NULL NULL NULL 1000 Using where 1 SIMPLE t3 ref b b 5 test.t2.b 1 Using where drop table t1, t2, t3; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, primary key(a)); +insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B; +explain select * from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 +show status like '%cost%'; +Variable_name Value +Last_query_cost 4.016090 +select 'The cost of accessing t1 (dont care if it changes' '^'; +The cost of accessing t1 (dont care if it changes +The cost of accessing t1 (dont care if it changes^ +select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z; +Z +vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv +explain select * from t1, t2 A, t2 B where A.a = t1.a and B.a=A.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 +1 SIMPLE A eq_ref PRIMARY PRIMARY 4 test.t1.a 1 +1 SIMPLE B eq_ref PRIMARY PRIMARY 4 test.A.b 1 +show status like '%cost%'; +Variable_name Value +Last_query_cost 24.016090 +select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z; +Z +^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error +drop table t1, t2; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 98bfb33b1e6..d0005f3b8f7 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -609,3 +609,24 @@ explain select * from t2,t3 where t2.a < 200 and t2.b=t3.b; drop table t1, t2, t3; +# BUG#14940 {Wrong query plan is chosen because of odd results of +# prev_record_reads() function } +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t2 (a int, b int, primary key(a)); +insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B; + +explain select * from t1; +show status like '%cost%'; +select 'The cost of accessing t1 (dont care if it changes' '^'; + +select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z; + +explain select * from t1, t2 A, t2 B where A.a = t1.a and B.a=A.b; +show status like '%cost%'; +select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z; + + + +drop table t1, t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7eda55c6a3f..a199b0a43bb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -70,7 +70,7 @@ static int join_tab_cmp_straight(const void* ptr1, const void* ptr2); static void find_best(JOIN *join,table_map rest_tables,uint index, double record_count,double read_time); static uint cache_record_length(JOIN *join,uint index); -static double prev_record_reads(JOIN *join,table_map found_ref); +static double prev_record_reads(JOIN *join, uint idx, table_map found_ref); static bool get_best_combination(JOIN *join); static store_key *get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, @@ -3373,6 +3373,7 @@ set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key) join->positions[idx].table= table; join->positions[idx].key=key; join->positions[idx].records_read=1.0; /* This is a const table */ + join->positions[idx].ref_depend_map= 0; /* Move the const table as down as possible in best_ref */ JOIN_TAB **pos=join->best_ref+idx+1; @@ -3430,6 +3431,7 @@ best_access_path(JOIN *join, double best= DBL_MAX; double best_time= DBL_MAX; double records= DBL_MAX; + table_map best_ref_depends_map; double tmp; ha_rows rec; @@ -3458,13 +3460,20 @@ best_access_path(JOIN *join, /* Calculate how many key segments of the current key we can use */ start_key= keyuse; - do - { /* for each keypart */ + + do /* For each keypart */ + { uint keypart= keyuse->keypart; table_map best_part_found_ref= 0; double best_prev_record_reads= DBL_MAX; - do + + do /* For each way to access the keypart */ { + + /* + if 1. expression doesn't refer to forward tables + 2. we won't get two ref-or-null's + */ if (!(remaining_tables & keyuse->used_tables) && !(ref_or_null_part && (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL))) @@ -3472,8 +3481,9 @@ best_access_path(JOIN *join, found_part|= keyuse->keypart_map; if (!(keyuse->used_tables & ~join->const_table_map)) const_part|= keyuse->keypart_map; - double tmp= prev_record_reads(join, (found_ref | - keyuse->used_tables)); + + double tmp= prev_record_reads(join, idx, (found_ref | + keyuse->used_tables)); if (tmp < best_prev_record_reads) { best_part_found_ref= keyuse->used_tables; @@ -3512,7 +3522,7 @@ best_access_path(JOIN *join, Really, there should be records=0.0 (yes!) but 1.0 would be probably safer */ - tmp= prev_record_reads(join, found_ref); + tmp= prev_record_reads(join, idx, found_ref); records= 1.0; } else @@ -3527,7 +3537,7 @@ best_access_path(JOIN *join, max_key_part= (uint) ~0; if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME) { - tmp = prev_record_reads(join, found_ref); + tmp = prev_record_reads(join, idx, found_ref); records=1.0; } else @@ -3757,6 +3767,7 @@ best_access_path(JOIN *join, best_records= records; best_key= start_key; best_max_key_part= max_key_part; + best_ref_depends_map= found_ref; } } records= best_records; @@ -3885,6 +3896,8 @@ best_access_path(JOIN *join, best= tmp; records= rows2double(rnd_records); best_key= 0; + /* range/index_merge/ALL/index access method are "independent", so: */ + best_ref_depends_map= 0; } } @@ -3893,6 +3906,7 @@ best_access_path(JOIN *join, join->positions[idx].read_time= best; join->positions[idx].key= best_key; join->positions[idx].table= s; + join->positions[idx].ref_depend_map= best_ref_depends_map; if (!best_key && idx == join->const_tables && @@ -4660,17 +4674,86 @@ cache_record_length(JOIN *join,uint idx) } +/* + Get the number of different row combinations for subset of partial join + + SYNOPSIS + prev_record_reads() + join The join structure + idx Number of tables in the partial join order (i.e. the + partial join order is in join->positions[0..idx-1]) + + found_ref Bitmap of tables for which we need to find # of distinct + row combinations. + + DESCRIPTION + Given a partial join order (in join->positions[0..idx-1]) and a subset of + tables within that join order (specified in found_ref), find out how many + distinct row combinations of subset tables will be in the result of the + partial join order. + + This is used as follows: Suppose we have a table accessed with a ref-based + method. The ref access depends on current rows of tables in found_ref. + We want to count # of different ref accesses. We assume two ref accesses + will be different if at least one of access parameters is different. + Example: consider a query + + SELECT * FROM t1, t2, t3 WHERE t1.key=c1 AND t2.key=c2 AND t3.key=t1.field + + and a join order: + t1, ref access on t1.key=c1 + t2, ref access on t2.key=c2 + t3, ref access on t3.key=t1.field + + For t1: n_ref_scans = 1, n_distinct_ref_scans = 1 + For t2: n_ref_scans = records_read(t1), n_distinct_ref_scans=1 + For t3: n_ref_scans = records_read(t1)*records_read(t2) + n_distinct_ref_scans = #records_read(t1) + + The reason for having this function (at least the latest version of it) + is that we need to account for buffering in join execution. + + An edge-case example: if we have a non-first table in join accessed via + ref(const) or ref(param) where there is a small number of different + values of param, then the access will likely hit the disk cache and will + not require any disk seeks. + + The proper solution would be to assume an LRU disk cache of some size, + calculate probability of cache hits, etc. For now we just count + identical ref accesses as one. + + RETURN + Expected number of row combinations +*/ + static double -prev_record_reads(JOIN *join,table_map found_ref) +prev_record_reads(JOIN *join, uint idx, table_map found_ref) { double found=1.0; - found_ref&= ~OUTER_REF_TABLE_BIT; - for (POSITION *pos=join->positions ; found_ref ; pos++) + POSITION *pos_end= join->positions - 1; + for (POSITION *pos= join->positions + idx - 1; pos != pos_end; pos--) { if (pos->table->table->map & found_ref) { - found_ref&= ~pos->table->table->map; - found*=pos->records_read; + found_ref|= pos->ref_depend_map; + /* + For the case of "t1 LEFT JOIN t2 ON ..." where t2 is a const table + with no matching row we will get position[t2].records_read==0. + Actually the size of output is one null-complemented row, therefore + we will use value of 1 whenever we get records_read==0. + + Note + - the above case can't occur if inner part of outer join has more + than one table: table with no matches will not be marked as const. + + - Ideally we should add 1 to records_read for every possible null- + complemented row. We're not doing it because: 1. it will require + non-trivial code and add overhead. 2. The value of records_read + is an inprecise estimate and adding 1 (or, in the worst case, + #max_nested_outer_joins=64-1) will not make it any more precise. + */ + if (pos->records_read) + found*= pos->records_read; } } return found; @@ -10242,6 +10325,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) tab->info="const row not found"; /* Mark for EXPLAIN that the row was not found */ pos->records_read=0.0; + pos->ref_depend_map= 0; if (!table->maybe_null || error > 0) DBUG_RETURN(error); } @@ -10267,6 +10351,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) tab->info="unique row not found"; /* Mark for EXPLAIN that the row was not found */ pos->records_read=0.0; + pos->ref_depend_map= 0; if (!table->maybe_null || error > 0) DBUG_RETURN(error); } diff --git a/sql/sql_select.h b/sql/sql_select.h index 3b0c312757d..eb6d2d5d34f 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -176,7 +176,13 @@ enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool */ typedef struct st_position { + /* + The "fanout": number of output rows that will be produced (after + pushed down selection condition is applied) per each row combination of + previous tables. + */ double records_read; + /* Cost accessing the table in course of the entire complete join execution, i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times @@ -184,7 +190,15 @@ typedef struct st_position */ double read_time; JOIN_TAB *table; + + /* + NULL - 'index' or 'range' or 'index_merge' or 'ALL' access is used. + Other - [eq_]ref[_or_null] access is used. Pointer to {t.keypart1 = expr} + */ KEYUSE *key; + + /* If ref-based access is used: bitmap of tables this table depends on */ + table_map ref_depend_map; } POSITION; From 8da0a672afacbdeb1291620d908ebc39b3205e3d Mon Sep 17 00:00:00 2001 From: "gkodinov@dl145s.mysql.com" <> Date: Fri, 29 Sep 2006 15:10:20 +0200 Subject: [PATCH 21/28] merge fixes --- mysql-test/t/view.test | 20 ++++++++++---------- sql/share/errmsg.txt | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 09ee7348606..934e0624fd6 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -347,13 +347,13 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; # try insert to VIEW with fields duplicate --- error 1471 +-- error 1573 insert into v3 values (-60,4,30); # try insert to VIEW with expression in SELECT list --- error 1471 +-- error 1573 insert into v4 values (-60,4,30); # try insert to VIEW using temporary table algorithm --- error 1471 +-- error 1573 insert into v5 values (-60,4,30); insert into v1 values (-60,4,30); insert into v1 (z,y,x) values (50,6,-100); @@ -375,13 +375,13 @@ create view v3 (x,y,z) as select b, a, b from t1; create view v4 (x,y,z) as select c+1, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; # try insert to VIEW with fields duplicate --- error 1471 +-- error 1573 insert into v3 select c, b, a from t2; # try insert to VIEW with expression in SELECT list --- error 1471 +-- error 1573 insert into v4 select c, b, a from t2; # try insert to VIEW using temporary table algorithm --- error 1471 +-- error 1573 insert into v5 select c, b, a from t2; insert into v1 select c, b, a from t2; insert into v1 (z,y,x) select a+20,b+2,-100 from t2; @@ -1249,14 +1249,14 @@ drop table t1; # create table t1 (s1 smallint); create view v1 as select * from t1 where 20 < (select (s1) from t1); --- error 1471 +-- error 1573 insert into v1 values (30); create view v2 as select * from t1; create view v3 as select * from t1 where 20 < (select (s1) from v2); --- error 1471 +-- error 1573 insert into v3 values (30); create view v4 as select * from v2 where 20 < (select (s1) from t1); --- error 1471 +-- error 1573 insert into v4 values (30); drop view v4, v3, v2, v1; drop table t1; @@ -2861,7 +2861,7 @@ DROP TABLE t1; # create table t1 (s1 int); create view v1 as select s1 as a, s1 as b from t1; ---error 1471 +--error 1573 insert into v1 values (1,1); update v1 set a = 5; drop view v1; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 51b91ece468..4cd11f9080c 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5986,10 +5986,10 @@ ER_HOSTNAME eng "host name" ER_WRONG_STRING_LENGTH eng "String '%-.70s' is too long for %s (should be no longer than %d)" -ER_NON_INSERTABLE_TABLE - eng "The target table %-.100s of the %s is not insertable-into" ER_UNSUPORTED_LOG_ENGINE eng "This storage engine cannot be used for log tables"" ER_BAD_LOG_STATEMENT eng "You cannot '%s' a log table if logging is enabled" +ER_NON_INSERTABLE_TABLE + eng "The target table %-.100s of the %s is not insertable-into" From e37d6ca7cd45dfb36e7be43a60cfe5574dce06bf Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Fri, 29 Sep 2006 18:26:57 +0400 Subject: [PATCH 22/28] Remove empty line --- sql/sql_select.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a199b0a43bb..085f0f9e2d3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4682,7 +4682,6 @@ cache_record_length(JOIN *join,uint idx) join The join structure idx Number of tables in the partial join order (i.e. the partial join order is in join->positions[0..idx-1]) - found_ref Bitmap of tables for which we need to find # of distinct row combinations. From cd094b71af6d418267c334fe9704656f68096647 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Fri, 29 Sep 2006 20:42:37 +0400 Subject: [PATCH 23/28] BUG#14940: Update test results --- mysql-test/r/greedy_optimizer.result | 16 ++++++++-------- mysql-test/r/order_by.result | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/greedy_optimizer.result b/mysql-test/r/greedy_optimizer.result index 1da49fbedb0..b02ff04780b 100644 --- a/mysql-test/r/greedy_optimizer.result +++ b/mysql-test/r/greedy_optimizer.result @@ -233,7 +233,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 @@ -245,7 +245,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 @@ -257,7 +257,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 @@ -269,7 +269,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 set optimizer_search_depth=1; select @@optimizer_search_depth; @@optimizer_search_depth @@ -385,7 +385,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 @@ -397,7 +397,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 @@ -409,7 +409,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 6 @@ -421,7 +421,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where show status like 'Last_query_cost'; Variable_name Value -Last_query_cost 274.418727 +Last_query_cost 289.418727 set optimizer_prune_level=1; select @@optimizer_prune_level; @@optimizer_prune_level diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 64653de5e9c..6461696b0d0 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -495,17 +495,17 @@ gid sid uid 103853 5 250 EXPLAIN select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t1.gid, t3.uid; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index -1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 test.t1.gid 1 +1 SIMPLE t2 ALL PRIMARY,uid NULL NULL NULL 6 Using temporary; Using filesort 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.gid 1 Using index EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t1.gid,t3.skr; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 ALL PRIMARY NULL NULL NULL 6 Using temporary; Using filesort 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t3.uid 1 Using where; Using index EXPLAIN SELECT t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index; Using temporary; Using filesort -1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 test.t1.gid 1 +1 SIMPLE t2 ALL PRIMARY,uid NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.gid 1 Using index 1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t3.skr,t1.gid; id select_type table type possible_keys key key_len ref rows Extra From a756fd36ef7f462a0103ad4b5a27f2e1c2924a93 Mon Sep 17 00:00:00 2001 From: "brian@zim.(none)" <> Date: Fri, 29 Sep 2006 17:19:02 -0700 Subject: [PATCH 24/28] This removes the passing of global hton to engine instance. --- sql/ha_ndbcluster.cc | 11 ++++++----- sql/ha_ndbcluster.h | 2 +- sql/ha_partition.cc | 16 +++++++++------- sql/ha_partition.h | 4 ++-- sql/handler.cc | 8 ++++---- sql/handler.h | 2 +- storage/archive/ha_archive.cc | 14 +++++++++----- storage/archive/ha_archive.h | 2 +- storage/blackhole/ha_blackhole.cc | 10 ++++++---- storage/blackhole/ha_blackhole.h | 2 +- storage/csv/ha_tina.cc | 14 +++++++++----- storage/csv/ha_tina.h | 2 +- storage/example/ha_example.cc | 14 +++++++++----- storage/example/ha_example.h | 2 +- storage/federated/ha_federated.cc | 13 ++++++++----- storage/federated/ha_federated.h | 2 +- storage/heap/ha_heap.cc | 14 +++++++++----- storage/heap/ha_heap.h | 2 +- storage/innobase/handler/ha_innodb.cc | 11 +++++++---- storage/innobase/handler/ha_innodb.h | 2 +- storage/myisam/ha_myisam.cc | 20 +++++++++++--------- storage/myisam/ha_myisam.h | 2 +- storage/myisammrg/ha_myisammrg.cc | 9 +++++---- storage/myisammrg/ha_myisammrg.h | 2 +- 24 files changed, 105 insertions(+), 75 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 157af825063..7203dc06e58 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -82,10 +82,11 @@ static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond) handlerton *ndbcluster_hton; -static handler *ndbcluster_create_handler(TABLE_SHARE *table, +static handler *ndbcluster_create_handler(handlerton *hton, + TABLE_SHARE *table, MEM_ROOT *mem_root) { - return new (mem_root) ha_ndbcluster(table); + return new (mem_root) ha_ndbcluster(hton, table); } static uint ndbcluster_partition_flags() @@ -5552,8 +5553,8 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, HA_HAS_OWN_BINLOGGING | \ HA_HAS_RECORDS -ha_ndbcluster::ha_ndbcluster(TABLE_SHARE *table_arg): - handler(ndbcluster_hton, table_arg), +ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg): + handler(hton, table_arg), m_active_trans(NULL), m_active_cursor(NULL), m_table(NULL), @@ -6623,7 +6624,7 @@ void ndbcluster_print_error(int error, const NdbOperation *error_op) share.db.length= 0; share.table_name.str= (char *) tab_name; share.table_name.length= strlen(tab_name); - ha_ndbcluster error_handler(&share); + ha_ndbcluster error_handler(ndbcluster_hton, &share); error_handler.print_error(error, MYF(0)); DBUG_VOID_RETURN; } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 5cd5bb2c716..19ff513f9b1 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -627,7 +627,7 @@ class Thd_ndb class ha_ndbcluster: public handler { public: - ha_ndbcluster(TABLE_SHARE *table); + ha_ndbcluster(handlerton *hton, TABLE_SHARE *table); ~ha_ndbcluster(); int ha_initialise(); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 8e704f34550..d2b05df5ffc 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -69,7 +69,8 @@ static PARTITION_SHARE *get_share(const char *table_name, TABLE * table); MODULE create/delete handler object ****************************************************************************/ -static handler *partition_create_handler(TABLE_SHARE *share, +static handler *partition_create_handler(handlerton *hton, + TABLE_SHARE *share, MEM_ROOT *mem_root); static uint partition_flags(); static uint alter_table_flags(uint flags); @@ -102,10 +103,11 @@ static int partition_initialize(void *p) New partition object */ -static handler *partition_create_handler(TABLE_SHARE *share, +static handler *partition_create_handler(handlerton *hton, + TABLE_SHARE *share, MEM_ROOT *mem_root) { - ha_partition *file= new (mem_root) ha_partition(share); + ha_partition *file= new (mem_root) ha_partition(hton, share); if (file && file->initialise_partition(mem_root)) { delete file; @@ -155,8 +157,8 @@ static uint alter_table_flags(uint flags __attribute__((unused))) NONE */ -ha_partition::ha_partition(TABLE_SHARE *share) - :handler(partition_hton, share), m_part_info(NULL), m_create_handler(FALSE), +ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share) + :handler(hton, share), m_part_info(NULL), m_create_handler(FALSE), m_is_sub_partitioned(0) { DBUG_ENTER("ha_partition::ha_partition(table)"); @@ -176,8 +178,8 @@ ha_partition::ha_partition(TABLE_SHARE *share) NONE */ -ha_partition::ha_partition(partition_info *part_info) - :handler(partition_hton, NULL), m_part_info(part_info), +ha_partition::ha_partition(handlerton *hton, partition_info *part_info) + :handler(hton, NULL), m_part_info(part_info), m_create_handler(TRUE), m_is_sub_partitioned(m_part_info->is_sub_partitioned()) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 97086d7b632..b66db205549 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -149,8 +149,8 @@ public: partition handler. ------------------------------------------------------------------------- */ - ha_partition(TABLE_SHARE * table); - ha_partition(partition_info * part_info); + ha_partition(handlerton *hton, TABLE_SHARE * table); + ha_partition(handlerton *hton, partition_info * part_info); ~ha_partition(); /* A partition handler has no characteristics in itself. It only inherits diff --git a/sql/handler.cc b/sql/handler.cc index 7848552f3de..bfb50653568 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -170,7 +170,7 @@ const char *ha_get_storage_engine(enum legacy_db_type db_type) static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root) { handlerton *hton= ha_default_handlerton(current_thd); - return (hton && hton->create) ? hton->create(table, mem_root) : NULL; + return (hton && hton->create) ? hton->create(hton, table, mem_root) : NULL; } @@ -232,7 +232,7 @@ handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc, if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create) { - if ((file= db_type->create(share, alloc))) + if ((file= db_type->create(db_type, share, alloc))) file->init(); DBUG_RETURN(file); } @@ -251,7 +251,7 @@ handler *get_ha_partition(partition_info *part_info) { ha_partition *partition; DBUG_ENTER("get_ha_partition"); - if ((partition= new ha_partition(part_info))) + if ((partition= new ha_partition(partition_hton, part_info))) { if (partition->initialise_partition(current_thd->mem_root)) { @@ -3296,7 +3296,7 @@ static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin, handlerton *hton= (handlerton *)plugin->data; handler *file; if (hton->state == SHOW_OPTION_YES && hton->create && - (file= hton->create((TABLE_SHARE*) 0, current_thd->mem_root))) + (file= hton->create(hton, (TABLE_SHARE*) 0, current_thd->mem_root))) { List_iterator_fast it(*found_exts); const char **ext, *old_ext; diff --git a/sql/handler.h b/sql/handler.h index 21ddb2c97d9..9bd06015b4a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -633,7 +633,7 @@ struct handlerton void *(*create_cursor_read_view)(); void (*set_cursor_read_view)(void *); void (*close_cursor_read_view)(void *); - handler *(*create)(TABLE_SHARE *table, MEM_ROOT *mem_root); + handler *(*create)(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); void (*drop_database)(char* path); int (*panic)(enum ha_panic_function flag); int (*start_consistent_snapshot)(THD *thd); diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 3971c4d73f0..a5a03f4f849 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -139,7 +139,9 @@ static HASH archive_open_tables; #define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption /* Static declarations for handerton */ -static handler *archive_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root); +static handler *archive_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root); /* Number of rows that will force a bulk insert. */ @@ -147,9 +149,11 @@ static handler *archive_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root); handlerton *archive_hton; -static handler *archive_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) +static handler *archive_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root) { - return new (mem_root) ha_archive(table); + return new (mem_root) ha_archive(hton, table); } /* @@ -231,8 +235,8 @@ int archive_db_end(ha_panic_function type) return archive_db_done(NULL); } -ha_archive::ha_archive(TABLE_SHARE *table_arg) - :handler(archive_hton, table_arg), delayed_insert(0), bulk_insert(0) +ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg) + :handler(hton, table_arg), delayed_insert(0), bulk_insert(0) { /* Set our original buffer from pre-allocated memory */ buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h index d1069afd87f..7f64f2f385d 100644 --- a/storage/archive/ha_archive.h +++ b/storage/archive/ha_archive.h @@ -67,7 +67,7 @@ class ha_archive: public handler uint current_k_offset; public: - ha_archive(TABLE_SHARE *table_arg); + ha_archive(handlerton *hton, TABLE_SHARE *table_arg); ~ha_archive() { } diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc index 2ebe43acd4d..c0ad28785bd 100644 --- a/storage/blackhole/ha_blackhole.cc +++ b/storage/blackhole/ha_blackhole.cc @@ -25,10 +25,11 @@ /* Static declarations for handlerton */ handlerton *blackhole_hton; -static handler *blackhole_create_handler(TABLE_SHARE *table, +static handler *blackhole_create_handler(handlerton *hton, + TABLE_SHARE *table, MEM_ROOT *mem_root) { - return new (mem_root) ha_blackhole(table); + return new (mem_root) ha_blackhole(hton, table); } @@ -36,8 +37,9 @@ static handler *blackhole_create_handler(TABLE_SHARE *table, ** BLACKHOLE tables *****************************************************************************/ -ha_blackhole::ha_blackhole(TABLE_SHARE *table_arg) - :handler(blackhole_hton, table_arg) +ha_blackhole::ha_blackhole(handlerton *hton, + TABLE_SHARE *table_arg) + :handler(hton, table_arg) {} diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h index 55c26f6f02e..54cec41fd26 100644 --- a/storage/blackhole/ha_blackhole.h +++ b/storage/blackhole/ha_blackhole.h @@ -28,7 +28,7 @@ class ha_blackhole: public handler THR_LOCK thr_lock; public: - ha_blackhole(TABLE_SHARE *table_arg); + ha_blackhole(handlerton *hton, TABLE_SHARE *table_arg); ~ha_blackhole() { } diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 8007ebfecd1..3cdfc04f2ce 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -74,7 +74,9 @@ static int write_meta_file(File meta_file, ha_rows rows, bool dirty); pthread_mutex_t tina_mutex; static HASH tina_open_tables; static int tina_init= 0; -static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root); +static handler *tina_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root); off_t Transparent_file::read_next() { @@ -493,14 +495,16 @@ off_t find_eoln_buff(Transparent_file *data_buff, off_t begin, } -static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) +static handler *tina_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root) { - return new (mem_root) ha_tina(table); + return new (mem_root) ha_tina(hton, table); } -ha_tina::ha_tina(TABLE_SHARE *table_arg) - :handler(tina_hton, table_arg), +ha_tina::ha_tina(handlerton *hton, TABLE_SHARE *table_arg) + :handler(hton, table_arg), /* These definitions are found in handler.h They are not probably completely right. diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h index 14ca848c855..d9537c42259 100644 --- a/storage/csv/ha_tina.h +++ b/storage/csv/ha_tina.h @@ -129,7 +129,7 @@ private: int init_tina_writer(); public: - ha_tina(TABLE_SHARE *table_arg); + ha_tina(handlerton *hton, TABLE_SHARE *table_arg); ~ha_tina() { if (chain_alloced) diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 1b49cbbae5a..68840a41879 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -73,7 +73,9 @@ #include -static handler *example_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root); +static handler *example_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root); static int example_init_func(); static bool example_init_func_for_handlerton(); static int example_panic(enum ha_panic_function flag); @@ -201,14 +203,16 @@ static int free_share(EXAMPLE_SHARE *share) } -static handler* example_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) +static handler* example_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root) { - return new (mem_root) ha_example(table); + return new (mem_root) ha_example(hton, table); } -ha_example::ha_example(TABLE_SHARE *table_arg) - :handler(example_hton, table_arg) +ha_example::ha_example(handlerton *hton, TABLE_SHARE *table_arg) + :handler(hton, table_arg) {} /* diff --git a/storage/example/ha_example.h b/storage/example/ha_example.h index 956dc62311c..2f5dbc29c56 100644 --- a/storage/example/ha_example.h +++ b/storage/example/ha_example.h @@ -45,7 +45,7 @@ class ha_example: public handler EXAMPLE_SHARE *share; /* Shared lock info */ public: - ha_example(TABLE_SHARE *table_arg); + ha_example(handlerton *hton, TABLE_SHARE *table_arg); ~ha_example() { } diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index ecfaa9dff2d..c7805e724f5 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -359,7 +359,8 @@ static const uint sizeof_trailing_and= sizeof(" AND ") - 1; static const uint sizeof_trailing_where= sizeof(" WHERE ") - 1; /* Static declaration for handerton */ -static handler *federated_create_handler(TABLE_SHARE *table, +static handler *federated_create_handler(handlerton *hton, + TABLE_SHARE *table, MEM_ROOT *mem_root); static int federated_commit(THD *thd, bool all); static int federated_rollback(THD *thd, bool all); @@ -368,10 +369,11 @@ static int federated_rollback(THD *thd, bool all); handlerton *federated_hton; -static handler *federated_create_handler(TABLE_SHARE *table, +static handler *federated_create_handler(handlerton *hton, + TABLE_SHARE *table, MEM_ROOT *mem_root) { - return new (mem_root) ha_federated(table); + return new (mem_root) ha_federated(hton, table); } @@ -723,8 +725,9 @@ error: ** FEDERATED tables *****************************************************************************/ -ha_federated::ha_federated(TABLE_SHARE *table_arg) - :handler(federated_hton, table_arg), +ha_federated::ha_federated(handlerton *hton, + TABLE_SHARE *table_arg) + :handler(hton, table_arg), mysql(0), stored_result(0) { trx_next= 0; diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h index ebdc775d3bf..385510960a6 100644 --- a/storage/federated/ha_federated.h +++ b/storage/federated/ha_federated.h @@ -94,7 +94,7 @@ private: int stash_remote_error(); public: - ha_federated(TABLE_SHARE *table_arg); + ha_federated(handlerton *hton, TABLE_SHARE *table_arg); ~ha_federated() {} /* The name that will be used for display purposes */ const char *table_type() const { return "FEDERATED"; } diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 1b76b24bd5d..5991fdbf987 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -25,7 +25,9 @@ #include "ha_heap.h" -static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root); +static handler *heap_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root); handlerton *heap_hton; @@ -41,9 +43,11 @@ int heap_init(void *p) return 0; } -static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) +static handler *heap_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root) { - return new (mem_root) ha_heap(table); + return new (mem_root) ha_heap(hton, table); } @@ -51,8 +55,8 @@ static handler *heap_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) ** HEAP tables *****************************************************************************/ -ha_heap::ha_heap(TABLE_SHARE *table_arg) - :handler(heap_hton, table_arg), file(0), records_changed(0), +ha_heap::ha_heap(handlerton *hton, TABLE_SHARE *table_arg) + :handler(hton, table_arg), file(0), records_changed(0), key_stat_version(0) {} diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h index 00e59856f26..0f6386655cb 100644 --- a/storage/heap/ha_heap.h +++ b/storage/heap/ha_heap.h @@ -31,7 +31,7 @@ class ha_heap: public handler uint records_changed; uint key_stat_version; public: - ha_heap(TABLE_SHARE *table); + ha_heap(handlerton *hton, TABLE_SHARE *table); ~ha_heap() {} const char *table_type() const { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8fa04246769..3fb0ab902e0 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -203,16 +203,19 @@ static int innobase_rollback(THD* thd, bool all); static int innobase_rollback_to_savepoint(THD* thd, void *savepoint); static int innobase_savepoint(THD* thd, void *savepoint); static int innobase_release_savepoint(THD* thd, void *savepoint); -static handler *innobase_create_handler(TABLE_SHARE *table, +static handler *innobase_create_handler(handlerton *hton, + TABLE_SHARE *table, MEM_ROOT *mem_root); static const char innobase_hton_name[]= "InnoDB"; handlerton *innobase_hton; -static handler *innobase_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) +static handler *innobase_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root) { - return new (mem_root) ha_innobase(table); + return new (mem_root) ha_innobase(hton, table); } @@ -889,7 +892,7 @@ check_trx_exists( /************************************************************************* Construct ha_innobase handler. */ -ha_innobase::ha_innobase(TABLE_SHARE *table_arg) +ha_innobase::ha_innobase(handlerton *hton, TABLE_SHARE *table_arg) :handler(innobase_hton, table_arg), int_table_flags(HA_REC_NOT_IN_SEQ | HA_NULL_IN_KEY | diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 4d5dc6b52d6..d87d9111139 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -80,7 +80,7 @@ class ha_innobase: public handler /* Init values for the class: */ public: - ha_innobase(TABLE_SHARE *table_arg); + ha_innobase(handlerton *hton, TABLE_SHARE *table_arg); ~ha_innobase() {} /* Get the row type from the storage engine. If this method returns diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index da4b4307f21..ae4dcfc3f8b 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -48,9 +48,11 @@ TYPELIB myisam_stats_method_typelib= { ** MyISAM tables *****************************************************************************/ -static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) +static handler *myisam_create_handler(handlerton *hton, + TABLE_SHARE *table, + MEM_ROOT *mem_root) { - return new (mem_root) ha_myisam(table); + return new (mem_root) ha_myisam(hton, table); } // collect errors printed by mi_check routines @@ -133,8 +135,8 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) } -ha_myisam::ha_myisam(TABLE_SHARE *table_arg) - :handler(myisam_hton, table_arg), file(0), +ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg) + :handler(hton, table_arg), file(0), int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS | @@ -1792,11 +1794,11 @@ handlerton *myisam_hton; static int myisam_init(void *p) { myisam_hton= (handlerton *)p; - myisam_hton->state=SHOW_OPTION_YES; - myisam_hton->db_type=DB_TYPE_MYISAM; - myisam_hton->create=myisam_create_handler; - myisam_hton->panic=mi_panic; - myisam_hton->flags=HTON_CAN_RECREATE; + myisam_hton->state= SHOW_OPTION_YES; + myisam_hton->db_type= DB_TYPE_MYISAM; + myisam_hton->create= myisam_create_handler; + myisam_hton->panic= mi_panic; + myisam_hton->flags= HTON_CAN_RECREATE; return 0; } diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index 511b796ebdb..85abcdca8b2 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -43,7 +43,7 @@ class ha_myisam: public handler int repair(THD *thd, MI_CHECK ¶m, bool optimize); public: - ha_myisam(TABLE_SHARE *table_arg); + ha_myisam(handlerton *hton, TABLE_SHARE *table_arg); ~ha_myisam() {} handler *clone(MEM_ROOT *mem_root); const char *table_type() const { return "MyISAM"; } diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index bc756e78023..54e5da320b5 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -38,15 +38,16 @@ static handler *myisammrg_create_handler(TABLE_SHARE *table, handlerton *myisammrg_hton; -static handler *myisammrg_create_handler(TABLE_SHARE *table, +static handler *myisammrg_create_handler(handlerton *hton, + TABLE_SHARE *table, MEM_ROOT *mem_root) { - return new (mem_root) ha_myisammrg(table); + return new (mem_root) ha_myisammrg(hton, table); } -ha_myisammrg::ha_myisammrg(TABLE_SHARE *table_arg) - :handler(myisammrg_hton, table_arg), file(0) +ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg) + :handler(hton, table_arg), file(0) {} static const char *ha_myisammrg_exts[] = { diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index d58a3523c26..faa3ae73c59 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -28,7 +28,7 @@ class ha_myisammrg: public handler MYRG_INFO *file; public: - ha_myisammrg(TABLE_SHARE *table_arg); + ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg); ~ha_myisammrg() {} const char *table_type() const { return "MRG_MyISAM"; } const char **bas_ext() const; From 46ae2113ba8a0d240469ba304b51ebebdd34942c Mon Sep 17 00:00:00 2001 From: "brian@zim.(none)" <> Date: Sat, 30 Sep 2006 12:49:46 -0700 Subject: [PATCH 25/28] This patch adds handlerton passing to functions. NDB and Innodb still require a global hanlderton in the main code due to the nature of the sql_cache call back function (should be solveable... another patch). Partitioning now has a flag to allow disabling of engines from being compatible with partitioning. Cleaned up heap naming convention on panic call. --- include/heap.h | 1 + sql/ha_ndbcluster.cc | 48 ++++--- sql/ha_ndbcluster_binlog.cc | 6 +- sql/handler.cc | 91 ++++++++----- sql/handler.h | 72 ++++++----- sql/log.cc | 29 +++-- sql/mysql_priv.h | 8 -- sql/mysqld.cc | 9 ++ sql/partition_info.cc | 3 +- sql/sql_cursor.cc | 12 +- sql/sql_show.cc | 2 +- sql/sql_tablespace.cc | 4 +- storage/archive/ha_archive.cc | 7 +- storage/archive/ha_archive.h | 2 - storage/blackhole/ha_blackhole.cc | 2 +- storage/csv/ha_tina.cc | 9 +- storage/csv/ha_tina.h | 2 - storage/federated/ha_federated.cc | 33 ++--- storage/federated/ha_federated.h | 3 - storage/heap/ha_heap.cc | 8 +- storage/heap/hp_panic.c | 6 +- storage/heap/hp_test1.c | 2 +- storage/heap/hp_test2.c | 4 +- storage/innobase/handler/ha_innodb.cc | 179 +++++++++++++++----------- storage/innobase/handler/ha_innodb.h | 23 ++-- storage/myisam/ha_myisam.cc | 11 +- storage/myisammrg/ha_myisammrg.cc | 22 ++-- 27 files changed, 350 insertions(+), 248 deletions(-) diff --git a/include/heap.h b/include/heap.h index 985b20f9dc9..69d1e441a4b 100644 --- a/include/heap.h +++ b/include/heap.h @@ -225,6 +225,7 @@ extern int heap_indexes_are_disabled(HP_INFO *info); extern void heap_update_auto_increment(HP_INFO *info, const byte *record); ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key, key_range *max_key); +int hp_panic(enum ha_panic_function flag); int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key, uint key_len, enum ha_rkey_function find_flag); extern gptr heap_find(HP_INFO *info,int inx,const byte *key); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 7203dc06e58..0d57f3decec 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -75,10 +75,17 @@ static const int max_transactions= 3; // should really be 2 but there is a trans static uint ndbcluster_partition_flags(); static uint ndbcluster_alter_table_flags(uint flags); static int ndbcluster_init(void *); -static int ndbcluster_end(ha_panic_function flag); -static bool ndbcluster_show_status(THD*,stat_print_fn *,enum ha_stat_type); -static int ndbcluster_alter_tablespace(THD* thd, st_alter_tablespace *info); -static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, COND *cond); +static int ndbcluster_end(handlerton *hton, ha_panic_function flag); +static bool ndbcluster_show_status(handlerton *hton, THD*, + stat_print_fn *, + enum ha_stat_type); +static int ndbcluster_alter_tablespace(handlerton *hton, + THD* thd, + st_alter_tablespace *info); +static int ndbcluster_fill_files_table(handlerton *hton, + THD *thd, + TABLE_LIST *tables, + COND *cond); handlerton *ndbcluster_hton; @@ -4202,7 +4209,7 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) Commit a transaction started in NDB */ -static int ndbcluster_commit(THD *thd, bool all) +static int ndbcluster_commit(handlerton *hton, THD *thd, bool all) { int res= 0; Thd_ndb *thd_ndb= get_thd_ndb(thd); @@ -4253,7 +4260,7 @@ static int ndbcluster_commit(THD *thd, bool all) Rollback a transaction started in NDB */ -static int ndbcluster_rollback(THD *thd, bool all) +static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all) { int res= 0; Thd_ndb *thd_ndb= get_thd_ndb(thd); @@ -5817,7 +5824,7 @@ int ha_ndbcluster::check_ndb_connection(THD* thd) } -static int ndbcluster_close_connection(THD *thd) +static int ndbcluster_close_connection(handlerton *hton, THD *thd) { Thd_ndb *thd_ndb= get_thd_ndb(thd); DBUG_ENTER("ndbcluster_close_connection"); @@ -5834,8 +5841,10 @@ static int ndbcluster_close_connection(THD *thd) Try to discover one table from NDB */ -int ndbcluster_discover(THD* thd, const char *db, const char *name, - const void** frmblob, uint* frmlen) +int ndbcluster_discover(handlerton *hton, THD* thd, const char *db, + const char *name, + const void** frmblob, + uint* frmlen) { int error= 0; NdbError ndb_error; @@ -5915,7 +5924,8 @@ err: */ -int ndbcluster_table_exists_in_engine(THD* thd, const char *db, +int ndbcluster_table_exists_in_engine(handlerton *hton, THD* thd, + const char *db, const char *name) { Ndb* ndb; @@ -6015,7 +6025,7 @@ int ndbcluster_drop_database_impl(const char *path) DBUG_RETURN(ret); } -static void ndbcluster_drop_database(char *path) +static void ndbcluster_drop_database(handlerton *hton, char *path) { THD *thd= current_thd; DBUG_ENTER("ndbcluster_drop_database"); @@ -6176,7 +6186,9 @@ int ndbcluster_find_all_files(THD *thd) DBUG_RETURN(-(skipped + unhandled)); } -int ndbcluster_find_files(THD *thd,const char *db,const char *path, +int ndbcluster_find_files(handlerton *hton, THD *thd, + const char *db, + const char *path, const char *wild, bool dir, List *files) { DBUG_ENTER("ndbcluster_find_files"); @@ -6286,7 +6298,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, DBUG_PRINT("info", ("%s existed on disk", name)); // The .ndb file exists on disk, but it's not in list of tables in ndb // Verify that handler agrees table is gone. - if (ndbcluster_table_exists_in_engine(thd, db, file_name) == 0) + if (ndbcluster_table_exists_in_engine(hton, thd, db, file_name) == 0) { DBUG_PRINT("info", ("NDB says %s does not exists", file_name)); it.remove(); @@ -6540,7 +6552,7 @@ ndbcluster_init_error: DBUG_RETURN(TRUE); } -static int ndbcluster_end(ha_panic_function type) +static int ndbcluster_end(handlerton *hton, ha_panic_function type) { DBUG_ENTER("ndbcluster_end"); @@ -9704,7 +9716,7 @@ err: Implements the SHOW NDB STATUS command. */ bool -ndbcluster_show_status(THD* thd, stat_print_fn *stat_print, +ndbcluster_show_status(handlerton *hton, THD* thd, stat_print_fn *stat_print, enum ha_stat_type stat_type) { char buf[IO_SIZE]; @@ -10168,7 +10180,7 @@ bool set_up_undofile(st_alter_tablespace *info, return false; } -int ndbcluster_alter_tablespace(THD* thd, st_alter_tablespace *info) +int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace *info) { DBUG_ENTER("ha_ndbcluster::alter_tablespace"); @@ -10429,7 +10441,9 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts) DBUG_RETURN(TRUE); } -static int ndbcluster_fill_files_table(THD *thd, TABLE_LIST *tables, +static int ndbcluster_fill_files_table(handlerton *hton, + THD *thd, + TABLE_LIST *tables, COND *cond) { TABLE* table= tables->table; diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 3fc84ad1b66..5f5c8bcb221 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -506,7 +506,7 @@ ndbcluster_binlog_index_purge_file(THD *thd, const char *file) } static void -ndbcluster_binlog_log_query(THD *thd, enum_binlog_command binlog_command, +ndbcluster_binlog_log_query(handlerton *hton, THD *thd, enum_binlog_command binlog_command, const char *query, uint query_length, const char *db, const char *table_name) { @@ -637,7 +637,9 @@ static void ndbcluster_reset_slave(THD *thd) /* Initialize the binlog part of the ndb handlerton */ -static int ndbcluster_binlog_func(THD *thd, enum_binlog_func fn, void *arg) +static int ndbcluster_binlog_func(handlerton *hton, THD *thd, + enum_binlog_func fn, + void *arg) { switch(fn) { diff --git a/sql/handler.cc b/sql/handler.cc index bfb50653568..bbb2cab5af2 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -376,7 +376,7 @@ int ha_finalize_handlerton(st_plugin_int *plugin) case SHOW_OPTION_YES: if (installed_htons[hton->db_type] == hton) installed_htons[hton->db_type]= NULL; - if (hton->panic && hton->panic(HA_PANIC_CLOSE)) + if (hton->panic && hton->panic(hton, HA_PANIC_CLOSE)) DBUG_RETURN(1); break; }; @@ -465,6 +465,28 @@ int ha_initialize_handlerton(st_plugin_int *plugin) hton->state= SHOW_OPTION_DISABLED; break; } + + /* + This is entirely for legacy. We will create a new "disk based" hton and a "memory" hton + which will be configurable longterm. + */ + switch (hton->db_type) { + case DB_TYPE_MRG_ISAM: + myisammrg_hton= hton; + break; + case DB_TYPE_HEAP: + heap_hton= hton; + break; + case DB_TYPE_MYISAM: + myisam_hton= hton; + break; + case DB_TYPE_PARTITION_DB: + partition_hton= hton; + break; + default: + break; + }; + DBUG_RETURN(0); err: DBUG_RETURN(1); @@ -498,7 +520,7 @@ static my_bool panic_handlerton(THD *unused1, st_plugin_int *plugin, void *arg) { handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->panic) - ((int*)arg)[0]|= hton->panic((enum ha_panic_function)((int*)arg)[1]); + ((int*)arg)[0]|= hton->panic(hton, (enum ha_panic_function)((int*)arg)[1]); return FALSE; } @@ -520,7 +542,7 @@ static my_bool dropdb_handlerton(THD *unused1, st_plugin_int *plugin, { handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->drop_database) - hton->drop_database((char *)path); + hton->drop_database(hton, (char *)path); return FALSE; } @@ -541,7 +563,7 @@ static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin, */ if (hton->state == SHOW_OPTION_YES && hton->close_connection && thd->ha_data[hton->slot]) - hton->close_connection(thd); + hton->close_connection(hton, thd); return FALSE; } @@ -617,7 +639,7 @@ int ha_prepare(THD *thd) statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status); if ((*ht)->prepare) { - if ((err= (*(*ht)->prepare)(thd, all))) + if ((err= (*(*ht)->prepare)(*ht, thd, all))) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); ha_rollback_trans(thd, all); @@ -691,7 +713,7 @@ int ha_commit_trans(THD *thd, bool all) for (; *ht && !error; ht++) { int err; - if ((err= (*(*ht)->prepare)(thd, all))) + if ((err= (*(*ht)->prepare)(*ht, thd, all))) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); error= 1; @@ -738,7 +760,7 @@ int ha_commit_one_phase(THD *thd, bool all) for (ht=trans->ht; *ht; ht++) { int err; - if ((err= (*(*ht)->commit)(thd, all))) + if ((err= (*(*ht)->commit)(*ht, thd, all))) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); error=1; @@ -794,7 +816,7 @@ int ha_rollback_trans(THD *thd, bool all) for (handlerton **ht=trans->ht; *ht; ht++) { int err; - if ((err= (*(*ht)->rollback)(thd, all))) + if ((err= (*(*ht)->rollback)(*ht, thd, all))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; @@ -871,7 +893,7 @@ static my_bool xacommit_handlerton(THD *unused1, st_plugin_int *plugin, handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->recover) { - hton->commit_by_xid(((struct xahton_st *)arg)->xid); + hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid); ((struct xahton_st *)arg)->result= 0; } return FALSE; @@ -883,7 +905,7 @@ static my_bool xarollback_handlerton(THD *unused1, st_plugin_int *plugin, handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->recover) { - hton->rollback_by_xid(((struct xahton_st *)arg)->xid); + hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid); ((struct xahton_st *)arg)->result= 0; } return FALSE; @@ -993,7 +1015,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin, if (hton->state == SHOW_OPTION_YES && hton->recover) { - while ((got= hton->recover(info->list, info->len)) > 0 ) + while ((got= hton->recover(hton, info->list, info->len)) > 0 ) { sql_print_information("Found %d prepared transaction(s) in %s", got, hton2plugin[hton->slot]->name.str); @@ -1024,7 +1046,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin, char buf[XIDDATASIZE*4+6]; // see xid_to_str sql_print_information("commit xid %s", xid_to_str(buf, info->list+i)); #endif - hton->commit_by_xid(info->list+i); + hton->commit_by_xid(hton, info->list+i); } else { @@ -1033,7 +1055,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin, sql_print_information("rollback xid %s", xid_to_str(buf, info->list+i)); #endif - hton->rollback_by_xid(info->list+i); + hton->rollback_by_xid(hton, info->list+i); } } if (got < info->len) @@ -1179,7 +1201,7 @@ static my_bool release_temporary_latches(THD *thd, st_plugin_int *plugin, handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches) - hton->release_temporary_latches(thd); + hton->release_temporary_latches(hton, thd); return FALSE; } @@ -1212,7 +1234,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) { int err; DBUG_ASSERT((*ht)->savepoint_set != 0); - if ((err= (*(*ht)->savepoint_rollback)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) + if ((err= (*(*ht)->savepoint_rollback)(*ht, thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; @@ -1228,7 +1250,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) for (; *ht ; ht++) { int err; - if ((err= (*(*ht)->rollback)(thd, !thd->in_sub_stmt))) + if ((err= (*(*ht)->rollback)(*ht, thd, !thd->in_sub_stmt))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; @@ -1262,7 +1284,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv) error=1; break; } - if ((err= (*(*ht)->savepoint_set)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) + if ((err= (*(*ht)->savepoint_set)(*ht, thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) { // cannot happen my_error(ER_GET_ERRNO, MYF(0), err); error=1; @@ -1288,7 +1310,9 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv) int err; if (!(*ht)->savepoint_release) continue; - if ((err= (*(*ht)->savepoint_release)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset))) + if ((err= (*(*ht)->savepoint_release)(*ht, thd, + (byte *)(sv+1)+ + (*ht)->savepoint_offset))) { // cannot happen my_error(ER_GET_ERRNO, MYF(0), err); error=1; @@ -1305,7 +1329,7 @@ static my_bool snapshot_handlerton(THD *thd, st_plugin_int *plugin, if (hton->state == SHOW_OPTION_YES && hton->start_consistent_snapshot) { - hton->start_consistent_snapshot(thd); + hton->start_consistent_snapshot(hton, thd); *((bool *)arg)= false; } return FALSE; @@ -1333,7 +1357,8 @@ static my_bool flush_handlerton(THD *thd, st_plugin_int *plugin, void *arg) { handlerton *hton= (handlerton *)plugin->data; - if (hton->state == SHOW_OPTION_YES && hton->flush_logs && hton->flush_logs()) + if (hton->state == SHOW_OPTION_YES && hton->flush_logs && + hton->flush_logs(hton)) return TRUE; return FALSE; } @@ -1350,7 +1375,7 @@ bool ha_flush_logs(handlerton *db_type) else { if (db_type->state != SHOW_OPTION_YES || - (db_type->flush_logs && db_type->flush_logs())) + (db_type->flush_logs && db_type->flush_logs(db_type))) return TRUE; } return FALSE; @@ -2765,7 +2790,9 @@ static my_bool discover_handlerton(THD *thd, st_plugin_int *plugin, st_discover_args *vargs= (st_discover_args *)arg; handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->discover && - (!(hton->discover(thd, vargs->db, vargs->name, vargs->frmblob, vargs->frmlen)))) + (!(hton->discover(hton, thd, vargs->db, vargs->name, + vargs->frmblob, + vargs->frmlen)))) return TRUE; return FALSE; @@ -2814,7 +2841,7 @@ static my_bool find_files_handlerton(THD *thd, st_plugin_int *plugin, if (hton->state == SHOW_OPTION_YES && hton->find_files) - if (hton->find_files(thd, vargs->db, vargs->path, vargs->wild, + if (hton->find_files(hton, thd, vargs->db, vargs->path, vargs->wild, vargs->dir, vargs->files)) return TRUE; @@ -2861,7 +2888,7 @@ static my_bool table_exists_in_engine_handlerton(THD *thd, st_plugin_int *plugin handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine) - if ((hton->table_exists_in_engine(thd, vargs->db, vargs->name)) == 1) + if ((hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name)) == 1) return TRUE; return FALSE; @@ -2930,7 +2957,7 @@ static my_bool binlog_func_foreach(THD *thd, binlog_func_st *bfn) uint i= 0, sz= hton_list.sz; while(i < sz) - hton_list.hton[i++]->binlog_func(thd, bfn->fn, bfn->arg); + hton_list.hton[i++]->binlog_func(hton, thd, bfn->fn, bfn->arg); return FALSE; } @@ -2977,12 +3004,12 @@ struct binlog_log_query_st }; static my_bool binlog_log_query_handlerton2(THD *thd, - const handlerton *hton, + handlerton *hton, void *args) { struct binlog_log_query_st *b= (struct binlog_log_query_st*)args; if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query) - hton->binlog_log_query(thd, + hton->binlog_log_query(hton, thd, b->binlog_command, b->query, b->query_length, @@ -2995,10 +3022,10 @@ static my_bool binlog_log_query_handlerton(THD *thd, st_plugin_int *plugin, void *args) { - return binlog_log_query_handlerton2(thd, (const handlerton *)plugin->data, args); + return binlog_log_query_handlerton2(thd, (handlerton *)plugin->data, args); } -void ha_binlog_log_query(THD *thd, const handlerton *hton, +void ha_binlog_log_query(THD *thd, handlerton *hton, enum_binlog_command binlog_command, const char *query, uint query_length, const char *db, const char *table_name) @@ -3371,7 +3398,7 @@ static my_bool showstat_handlerton(THD *thd, st_plugin_int *plugin, enum ha_stat_type stat= *(enum ha_stat_type *) arg; handlerton *hton= (handlerton *)plugin->data; if (hton->state == SHOW_OPTION_YES && hton->show_status && - hton->show_status(thd, stat_print, stat)) + hton->show_status(hton, thd, stat_print, stat)) return TRUE; return FALSE; } @@ -3405,7 +3432,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) } else result= db_type->show_status && - db_type->show_status(thd, stat_print, stat) ? 1 : 0; + db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0; } if (!result) @@ -3726,7 +3753,7 @@ int example_of_iterator_using_for_logs_cleanup(handlerton *hton) if (!hton->create_iterator) return 1; /* iterator creator is not supported */ - if ((*hton->create_iterator)(HA_TRANSACTLOG_ITERATOR, &iterator) != + if ((*hton->create_iterator)(hton, HA_TRANSACTLOG_ITERATOR, &iterator) != HA_ITERATOR_OK) { /* error during creation of log iterator or iterator is not supported */ diff --git a/sql/handler.h b/sql/handler.h index 9bd06015b4a..c873eecbef6 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -449,7 +449,7 @@ class st_alter_tablespace : public Sql_alloc ulonglong autoextend_size; ulonglong max_size; uint nodegroup_id; - const handlerton *storage_engine; + handlerton *storage_engine; bool wait_until_completed; const char *ts_comment; enum tablespace_access_mode ts_access_mode; @@ -605,18 +605,18 @@ struct handlerton this storage area - set it to something, so that MySQL would know this storage engine was accessed in this connection */ - int (*close_connection)(THD *thd); + int (*close_connection)(handlerton *hton, THD *thd); /* sv points to an uninitialized storage area of requested size (see savepoint_offset description) */ - int (*savepoint_set)(THD *thd, void *sv); + int (*savepoint_set)(handlerton *hton, THD *thd, void *sv); /* sv points to a storage area, that was earlier passed to the savepoint_set call */ - int (*savepoint_rollback)(THD *thd, void *sv); - int (*savepoint_release)(THD *thd, void *sv); + int (*savepoint_rollback)(handlerton *hton, THD *thd, void *sv); + int (*savepoint_release)(handlerton *hton, THD *thd, void *sv); /* 'all' is true if it's a real commit, that makes persistent changes 'all' is false if it's not in fact a commit but an end of the @@ -624,25 +624,25 @@ struct handlerton NOTE 'all' is also false in auto-commit mode where 'end of statement' and 'real commit' mean the same event. */ - int (*commit)(THD *thd, bool all); - int (*rollback)(THD *thd, bool all); - int (*prepare)(THD *thd, bool all); - int (*recover)(XID *xid_list, uint len); - int (*commit_by_xid)(XID *xid); - int (*rollback_by_xid)(XID *xid); - void *(*create_cursor_read_view)(); - void (*set_cursor_read_view)(void *); - void (*close_cursor_read_view)(void *); + int (*commit)(handlerton *hton, THD *thd, bool all); + int (*rollback)(handlerton *hton, THD *thd, bool all); + int (*prepare)(handlerton *hton, THD *thd, bool all); + int (*recover)(handlerton *hton, XID *xid_list, uint len); + int (*commit_by_xid)(handlerton *hton, XID *xid); + int (*rollback_by_xid)(handlerton *hton, XID *xid); + void *(*create_cursor_read_view)(handlerton *hton); + void (*set_cursor_read_view)(handlerton *hton, void *); + void (*close_cursor_read_view)(handlerton *hton, void *); handler *(*create)(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); - void (*drop_database)(char* path); - int (*panic)(enum ha_panic_function flag); - int (*start_consistent_snapshot)(THD *thd); - bool (*flush_logs)(); - bool (*show_status)(THD *thd, stat_print_fn *print, enum ha_stat_type stat); + void (*drop_database)(handlerton *hton, char* path); + int (*panic)(handlerton *hton, enum ha_panic_function flag); + int (*start_consistent_snapshot)(handlerton *hton, THD *thd); + bool (*flush_logs)(handlerton *hton); + bool (*show_status)(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat); uint (*partition_flags)(); uint (*alter_table_flags)(uint flags); - int (*alter_tablespace)(THD *thd, st_alter_tablespace *ts_info); - int (*fill_files_table)(THD *thd, + int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info); + int (*fill_files_table)(handlerton *hton, THD *thd, struct st_table_list *tables, class Item *cond); uint32 flags; /* global handler flags */ @@ -650,11 +650,12 @@ struct handlerton Those handlerton functions below are properly initialized at handler init. */ - int (*binlog_func)(THD *thd, enum_binlog_func fn, void *arg); - void (*binlog_log_query)(THD *thd, enum_binlog_command binlog_command, + int (*binlog_func)(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg); + void (*binlog_log_query)(handlerton *hton, THD *thd, + enum_binlog_command binlog_command, const char *query, uint query_length, const char *db, const char *table_name); - int (*release_temporary_latches)(THD *thd); + int (*release_temporary_latches)(handlerton *hton, THD *thd); /* Get log status. @@ -663,20 +664,24 @@ struct handlerton (see example of implementation in handler.cc, TRANS_LOG_MGM_EXAMPLE_CODE) */ - enum log_status (*get_log_status)(char *log); + enum log_status (*get_log_status)(handlerton *hton, char *log); /* Iterators creator. Presence of the pointer should be checked before using */ enum handler_create_iterator_result - (*create_iterator)(enum handler_iterator_type type, + (*create_iterator)(handlerton *hton, enum handler_iterator_type type, struct handler_iterator *fill_this_in); - int (*discover)(THD* thd, const char *db, const char *name, - const void** frmblob, uint* frmlen); - int (*find_files)(THD *thd,const char *db,const char *path, + int (*discover)(handlerton *hton, THD* thd, const char *db, + const char *name, + const void** frmblob, + uint* frmlen); + int (*find_files)(handlerton *hton, THD *thd, + const char *db, + const char *path, const char *wild, bool dir, List *files); - int (*table_exists_in_engine)(THD* thd, const char *db, + int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db, const char *name); }; @@ -690,6 +695,7 @@ struct handlerton #define HTON_FLUSH_AFTER_RENAME (1 << 4) #define HTON_NOT_USER_SELECTABLE (1 << 5) #define HTON_TEMPORARY_NOT_SUPPORTED (1 << 6) //Having temporary tables not supported +#define HTON_NO_PARTITION (1 << 7) //You can not partition these tables typedef struct st_thd_trans { @@ -892,7 +898,7 @@ class handler :public Sql_alloc virtual void start_bulk_insert(ha_rows rows) {} virtual int end_bulk_insert() {return 0; } public: - const handlerton *ht; /* storage engine of this handler */ + handlerton *ht; /* storage engine of this handler */ byte *ref; /* Pointer to current row */ byte *dup_ref; /* Pointer to duplicate row */ @@ -942,7 +948,7 @@ public: */ Discrete_interval auto_inc_interval_for_cur_row; - handler(const handlerton *ht_arg, TABLE_SHARE *share_arg) + handler(handlerton *ht_arg, TABLE_SHARE *share_arg) :table_share(share_arg), estimation_rows_to_insert(0), ht(ht_arg), ref(0), key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), @@ -1715,7 +1721,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht); int ha_reset_logs(THD *thd); int ha_binlog_index_purge_file(THD *thd, const char *file); void ha_reset_slave(THD *thd); -void ha_binlog_log_query(THD *thd, const handlerton *db_type, +void ha_binlog_log_query(THD *thd, handlerton *db_type, enum_binlog_command binlog_command, const char *query, uint query_length, const char *db, const char *table_name); diff --git a/sql/log.cc b/sql/log.cc index 9c2efb04a44..05758fd6e7d 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -46,13 +46,13 @@ static Muted_query_log_event invisible_commit; static bool test_if_number(const char *str, long *res, bool allow_wildcards); -static int binlog_init(); -static int binlog_close_connection(THD *thd); -static int binlog_savepoint_set(THD *thd, void *sv); -static int binlog_savepoint_rollback(THD *thd, void *sv); -static int binlog_commit(THD *thd, bool all); -static int binlog_rollback(THD *thd, bool all); -static int binlog_prepare(THD *thd, bool all); +static int binlog_init(void *p); +static int binlog_close_connection(handlerton *hton, THD *thd); +static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv); +static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv); +static int binlog_commit(handlerton *hton, THD *thd, bool all); +static int binlog_rollback(handlerton *hton, THD *thd, bool all); +static int binlog_prepare(handlerton *hton, THD *thd, bool all); sql_print_message_func sql_print_message_handlers[3] = { @@ -1171,7 +1171,7 @@ int binlog_init(void *p) return 0; } -static int binlog_close_connection(THD *thd) +static int binlog_close_connection(handlerton *hton, THD *thd) { binlog_trx_data *const trx_data= (binlog_trx_data*) thd->ha_data[binlog_hton->slot]; @@ -1184,7 +1184,8 @@ static int binlog_close_connection(THD *thd) } static int -binlog_end_trans(THD *thd, binlog_trx_data *trx_data, Log_event *end_ev) +binlog_end_trans(THD *thd, binlog_trx_data *trx_data, + Log_event *end_ev) { DBUG_ENTER("binlog_end_trans"); int error=0; @@ -1238,7 +1239,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, Log_event *end_ev) DBUG_RETURN(error); } -static int binlog_prepare(THD *thd, bool all) +static int binlog_prepare(handlerton *hton, THD *thd, bool all) { /* do nothing. @@ -1249,7 +1250,7 @@ static int binlog_prepare(THD *thd, bool all) return 0; } -static int binlog_commit(THD *thd, bool all) +static int binlog_commit(handlerton *hton, THD *thd, bool all) { DBUG_ENTER("binlog_commit"); binlog_trx_data *const trx_data= @@ -1273,7 +1274,7 @@ static int binlog_commit(THD *thd, bool all) DBUG_RETURN(binlog_end_trans(thd, trx_data, &invisible_commit)); } -static int binlog_rollback(THD *thd, bool all) +static int binlog_rollback(handlerton *hton, THD *thd, bool all) { DBUG_ENTER("binlog_rollback"); int error=0; @@ -1326,7 +1327,7 @@ static int binlog_rollback(THD *thd, bool all) that case there is no need to have it in the binlog). */ -static int binlog_savepoint_set(THD *thd, void *sv) +static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) { DBUG_ENTER("binlog_savepoint_set"); binlog_trx_data *const trx_data= @@ -1342,7 +1343,7 @@ static int binlog_savepoint_set(THD *thd, void *sv) DBUG_RETURN(error); } -static int binlog_savepoint_rollback(THD *thd, void *sv) +static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) { DBUG_ENTER("binlog_savepoint_rollback"); binlog_trx_data *const trx_data= diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dcd0624564c..9cd8e36c996 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1638,19 +1638,11 @@ extern SHOW_COMP_OPTION have_ndbcluster; extern SHOW_COMP_OPTION have_partition_db; extern SHOW_COMP_OPTION have_merge_db; -#ifdef WITH_CSV_STORAGE_ENGINE -extern handlerton *tina_hton; -#endif #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE extern handlerton *ndbcluster_hton; #endif -#ifdef WITH_PARTITION_STORAGE_ENGINE extern handlerton *partition_hton; -#endif -#ifdef WITH_MYISAMMRG_STORAGE_ENGINE extern handlerton *myisammrg_hton; -#endif - extern handlerton *myisam_hton; extern handlerton *heap_hton; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a3844ea8fc0..d820e2f4192 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -354,6 +354,15 @@ my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; my_bool opt_log_slave_updates= 0; my_bool opt_innodb; + +/* + Legacy global handlerton. These will be removed (please do not add more). +*/ +handlerton *ndbclusert_hton; +handlerton *myisammrg_hton; +handlerton *heap_hton; +handlerton *myisam_hton; + #ifdef WITH_INNOBASE_STORAGE_ENGINE extern ulong innobase_fast_shutdown; extern ulong innobase_large_page_size; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3e8ad9bb78b..3210eb0675e 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -443,8 +443,7 @@ bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts) DBUG_RETURN(TRUE); } } while (++i < no_parts); - if (engine_array[0] == myisammrg_hton || - engine_array[0] == tina_hton) + if (engine_array[0]->flags & HTON_NO_PARTITION) { my_error(ER_PARTITION_MERGE_ERROR, MYF(0), engine_array[0] == myisammrg_hton ? "MyISAM Merge" : "CSV"); diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 2784e71ccae..abf8e30b1ab 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -45,7 +45,7 @@ class Sensitive_cursor: public Server_side_cursor query_id_t query_id; struct Engine_info { - const handlerton *ht; + handlerton *ht; void *read_view; }; Engine_info ht_info[MAX_HA]; @@ -318,12 +318,12 @@ Sensitive_cursor::post_open(THD *thd) info= &ht_info[0]; for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++) { - const handlerton *ht= *pht; + handlerton *ht= *pht; close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); if (ht->create_cursor_read_view) { info->ht= ht; - info->read_view= (ht->create_cursor_read_view)(); + info->read_view= (ht->create_cursor_read_view)(ht); ++info; } } @@ -433,7 +433,7 @@ Sensitive_cursor::fetch(ulong num_rows) thd->set_n_backup_active_arena(this, &backup_arena); for (info= ht_info; info->read_view ; info++) - (info->ht->set_cursor_read_view)(info->read_view); + (info->ht->set_cursor_read_view)(info->ht, info->read_view); join->fetch_limit+= num_rows; @@ -454,7 +454,7 @@ Sensitive_cursor::fetch(ulong num_rows) reset_thd(thd); for (info= ht_info; info->read_view; info++) - (info->ht->set_cursor_read_view)(0); + (info->ht->set_cursor_read_view)(info->ht, 0); if (error == NESTED_LOOP_CURSOR_LIMIT) { @@ -487,7 +487,7 @@ Sensitive_cursor::close() for (Engine_info *info= ht_info; info->read_view; info++) { - (info->ht->close_cursor_read_view)(info->read_view); + (info->ht->close_cursor_read_view)(info->ht, info->read_view); info->read_view= 0; info->ht= 0; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 709184e1c3d..9e2647647ce 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5001,7 +5001,7 @@ static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin, (run_hton_fill_schema_files_args *) arg; handlerton *hton= (handlerton *)plugin->data; if(hton->fill_files_table && hton->state == SHOW_OPTION_YES) - hton->fill_files_table(thd, args->tables, args->cond); + hton->fill_files_table(hton, thd, args->tables, args->cond); return false; } diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc index 13dfb491af4..470fa5bc862 100644 --- a/sql/sql_tablespace.cc +++ b/sql/sql_tablespace.cc @@ -21,7 +21,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info) { int error= HA_ADMIN_NOT_IMPLEMENTED; - const handlerton *hton= ts_info->storage_engine; + handlerton *hton= ts_info->storage_engine; DBUG_ENTER("mysql_alter_tablespace"); /* @@ -42,7 +42,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info) if (hton->alter_tablespace) { - if ((error= hton->alter_tablespace(thd, ts_info))) + if ((error= hton->alter_tablespace(hton, thd, ts_info))) { if (error == HA_ADMIN_NOT_IMPLEMENTED) { diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index a5a03f4f849..0fd5f0ed099 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -142,13 +142,13 @@ static HASH archive_open_tables; static handler *archive_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +int archive_db_end(handlerton *hton, ha_panic_function type); + /* Number of rows that will force a bulk insert. */ #define ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT 2 -handlerton *archive_hton; - static handler *archive_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) @@ -182,6 +182,7 @@ static byte* archive_get_key(ARCHIVE_SHARE *share,uint *length, int archive_db_init(void *p) { DBUG_ENTER("archive_db_init"); + handlerton *archive_hton; if (archive_inited) DBUG_RETURN(FALSE); archive_hton= (handlerton *)p; @@ -230,7 +231,7 @@ int archive_db_done(void *p) } -int archive_db_end(ha_panic_function type) +int archive_db_end(handlerton *hton, ha_panic_function type) { return archive_db_done(NULL); } diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h index 7f64f2f385d..1a601c8451a 100644 --- a/storage/archive/ha_archive.h +++ b/storage/archive/ha_archive.h @@ -139,5 +139,3 @@ public: bool check_and_repair(THD *thd); }; -int archive_db_end(ha_panic_function type); - diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc index c0ad28785bd..7ab32cccf84 100644 --- a/storage/blackhole/ha_blackhole.cc +++ b/storage/blackhole/ha_blackhole.cc @@ -24,7 +24,6 @@ /* Static declarations for handlerton */ -handlerton *blackhole_hton; static handler *blackhole_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) @@ -205,6 +204,7 @@ int ha_blackhole::index_last(byte * buf) static int blackhole_init(void *p) { + handlerton *blackhole_hton; blackhole_hton= (handlerton *)p; blackhole_hton->state= SHOW_OPTION_YES; blackhole_hton->db_type= DB_TYPE_BLACKHOLE_DB; diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 3cdfc04f2ce..24e063672f5 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -77,6 +77,8 @@ static int tina_init= 0; static handler *tina_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +int tina_end(handlerton *hton, ha_panic_function type); + off_t Transparent_file::read_next() { @@ -125,7 +127,6 @@ char Transparent_file::get_value(off_t offset) return buff[0]; } } -handlerton *tina_hton; /***************************************************************************** ** TINA tables @@ -152,6 +153,8 @@ static byte* tina_get_key(TINA_SHARE *share,uint *length, static int tina_init_func(void *p) { + handlerton *tina_hton; + if (!tina_init) { tina_hton= (handlerton *)p; @@ -163,7 +166,7 @@ static int tina_init_func(void *p) tina_hton->db_type= DB_TYPE_CSV_DB; tina_hton->create= tina_create_handler; tina_hton->panic= tina_end; - tina_hton->flags= HTON_CAN_RECREATE; + tina_hton->flags= HTON_CAN_RECREATE|HTON_NO_PARTITION; } return 0; } @@ -451,7 +454,7 @@ static int free_share(TINA_SHARE *share) DBUG_RETURN(result_code); } -int tina_end(ha_panic_function type) +int tina_end(handlerton *hton, ha_panic_function type) { return tina_done_func(NULL); } diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h index d9537c42259..f408e8f4a7d 100644 --- a/storage/csv/ha_tina.h +++ b/storage/csv/ha_tina.h @@ -212,5 +212,3 @@ public: int chain_append(); }; -int tina_end(ha_panic_function type); - diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index c7805e724f5..3c1cc722f02 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -362,13 +362,14 @@ static const uint sizeof_trailing_where= sizeof(" WHERE ") - 1; static handler *federated_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); -static int federated_commit(THD *thd, bool all); -static int federated_rollback(THD *thd, bool all); +static int federated_commit(handlerton *hton, THD *thd, bool all); +static int federated_rollback(handlerton *hton, THD *thd, bool all); +static int federated_db_init(void); +static int federated_db_end(handlerton *hton, ha_panic_function type); + /* Federated storage engine handlerton */ -handlerton *federated_hton; - static handler *federated_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) @@ -401,7 +402,7 @@ static byte *federated_get_key(FEDERATED_SHARE *share, uint *length, int federated_db_init(void *p) { DBUG_ENTER("federated_db_init"); - federated_hton= (handlerton *)p; + handlerton *federated_hton= (handlerton *)p; federated_hton->state= SHOW_OPTION_YES; federated_hton->db_type= DB_TYPE_FEDERATED_DB; federated_hton->commit= federated_commit; @@ -436,7 +437,7 @@ error: FALSE OK */ -int federated_db_end(ha_panic_function type) +int federated_db_end(handlerton *hton, ha_panic_function type) { if (federated_init) { @@ -2739,7 +2740,7 @@ bool ha_federated::get_error_message(int error, String* buf) int ha_federated::external_lock(THD *thd, int lock_type) { int error= 0; - ha_federated *trx= (ha_federated *)thd->ha_data[federated_hton->slot]; + ha_federated *trx= (ha_federated *)thd->ha_data[ht->slot]; DBUG_ENTER("ha_federated::external_lock"); if (lock_type != F_UNLCK) @@ -2757,7 +2758,7 @@ int ha_federated::external_lock(THD *thd, int lock_type) DBUG_PRINT("info", ("error setting autocommit TRUE: %d", error)); DBUG_RETURN(error); } - trans_register_ha(thd, FALSE, federated_hton); + trans_register_ha(thd, FALSE, ht); } else { @@ -2773,8 +2774,8 @@ int ha_federated::external_lock(THD *thd, int lock_type) DBUG_PRINT("info", ("error setting autocommit FALSE: %d", error)); DBUG_RETURN(error); } - thd->ha_data[federated_hton->slot]= this; - trans_register_ha(thd, TRUE, federated_hton); + thd->ha_data[ht->slot]= this; + trans_register_ha(thd, TRUE, ht); /* Send a lock table to the remote end. We do not support this at the moment @@ -2799,10 +2800,10 @@ int ha_federated::external_lock(THD *thd, int lock_type) } -static int federated_commit(THD *thd, bool all) +static int federated_commit(handlerton *hton, THD *thd, bool all) { int return_val= 0; - ha_federated *trx= (ha_federated *)thd->ha_data[federated_hton->slot]; + ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot]; DBUG_ENTER("federated_commit"); if (all) @@ -2817,7 +2818,7 @@ static int federated_commit(THD *thd, bool all) if (error && !return_val); return_val= error; } - thd->ha_data[federated_hton->slot]= NULL; + thd->ha_data[hton->slot]= NULL; } DBUG_PRINT("info", ("error val: %d", return_val)); @@ -2825,10 +2826,10 @@ static int federated_commit(THD *thd, bool all) } -static int federated_rollback(THD *thd, bool all) +static int federated_rollback(handlerton *hton, THD *thd, bool all) { int return_val= 0; - ha_federated *trx= (ha_federated *)thd->ha_data[federated_hton->slot]; + ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot]; DBUG_ENTER("federated_rollback"); if (all) @@ -2843,7 +2844,7 @@ static int federated_rollback(THD *thd, bool all) if (error && !return_val) return_val= error; } - thd->ha_data[federated_hton->slot]= NULL; + thd->ha_data[hton->slot]= NULL; } DBUG_PRINT("info", ("error val: %d", return_val)); diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h index 385510960a6..ade1e5b181e 100644 --- a/storage/federated/ha_federated.h +++ b/storage/federated/ha_federated.h @@ -236,6 +236,3 @@ public: MYSQL_RES **result); }; -int federated_db_init(void); -int federated_db_end(ha_panic_function type); - diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 5991fdbf987..4a83b2e12d8 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -29,10 +29,16 @@ static handler *heap_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); -handlerton *heap_hton; +int heap_panic(handlerton *hton, ha_panic_function flag) +{ + return hp_panic(flag); +} + int heap_init(void *p) { + handlerton *heap_hton; + heap_hton= (handlerton *)p; heap_hton->state= SHOW_OPTION_YES; heap_hton->db_type= DB_TYPE_HEAP; diff --git a/storage/heap/hp_panic.c b/storage/heap/hp_panic.c index 2b659cbfbb3..08c310bec3d 100644 --- a/storage/heap/hp_panic.c +++ b/storage/heap/hp_panic.c @@ -19,10 +19,10 @@ /* if flag == HA_PANIC_CLOSE then all files are removed for more memory */ -int heap_panic(enum ha_panic_function flag) +int hp_panic(enum ha_panic_function flag) { LIST *element,*next_open; - DBUG_ENTER("heap_panic"); + DBUG_ENTER("hp_panic"); pthread_mutex_lock(&THR_LOCK_heap); for (element=heap_open_list ; element ; element=next_open) @@ -54,4 +54,4 @@ int heap_panic(enum ha_panic_function flag) } pthread_mutex_unlock(&THR_LOCK_heap); DBUG_RETURN(0); -} /* heap_panic */ +} /* hp_panic */ diff --git a/storage/heap/hp_test1.c b/storage/heap/hp_test1.c index 703b39b1e2d..a7423effac8 100644 --- a/storage/heap/hp_test1.c +++ b/storage/heap/hp_test1.c @@ -155,7 +155,7 @@ int main(int argc, char **argv) } #endif - if (heap_close(file) || heap_panic(HA_PANIC_CLOSE)) + if (heap_close(file) || hp_panic(HA_PANIC_CLOSE)) goto err; my_end(MY_GIVE_INFO); return(0); diff --git a/storage/heap/hp_test2.c b/storage/heap/hp_test2.c index c1d987a3b5f..b4e8cf98f0b 100644 --- a/storage/heap/hp_test2.c +++ b/storage/heap/hp_test2.c @@ -603,7 +603,7 @@ end: if (heap_close(file) || (file2 && heap_close(file2))) goto err; heap_delete_table(filename2); - heap_panic(HA_PANIC_CLOSE); + hp_panic(HA_PANIC_CLOSE); my_end(MY_GIVE_INFO); return(0); err: @@ -669,7 +669,7 @@ static sig_handler endprog(int sig_number __attribute__((unused))) else #endif { - heap_panic(HA_PANIC_CLOSE); + hp_panic(HA_PANIC_CLOSE); my_end(1); exit(1); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3fb0ab902e0..43627f84f2d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -54,6 +54,12 @@ pthread_cond_t commit_cond; pthread_mutex_t commit_cond_m; bool innodb_inited= 0; +/* + This needs to exist until the query cache callback is removed + or learns to pass hton. +*/ +static handlerton *legacy_innodb_hton; + /*-----------------------------------------------------------------*/ /* These variables are used to implement (semi-)synchronous MySQL binlog replication for InnoDB tables. */ @@ -197,20 +203,20 @@ static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length, my_bool not_used __attribute__((unused))); static INNOBASE_SHARE *get_share(const char *table_name); static void free_share(INNOBASE_SHARE *share); -static int innobase_close_connection(THD* thd); -static int innobase_commit(THD* thd, bool all); -static int innobase_rollback(THD* thd, bool all); -static int innobase_rollback_to_savepoint(THD* thd, void *savepoint); -static int innobase_savepoint(THD* thd, void *savepoint); -static int innobase_release_savepoint(THD* thd, void *savepoint); +static int innobase_close_connection(handlerton *hton, THD* thd); +static int innobase_commit(handlerton *hton, THD* thd, bool all); +static int innobase_rollback(handlerton *hton, THD* thd, bool all); +static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, + void *savepoint); +static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); +static int innobase_release_savepoint(handlerton *hton, THD* thd, + void *savepoint); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); static const char innobase_hton_name[]= "InnoDB"; -handlerton *innobase_hton; - static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) @@ -383,7 +389,8 @@ documentation, see handler.cc. */ int innobase_release_temporary_latches( /*===============================*/ - THD *thd) + handlerton *hton, + THD *thd) { trx_t* trx; @@ -392,7 +399,7 @@ innobase_release_temporary_latches( return 0; } - trx = (trx_t*) thd->ha_data[innobase_hton->slot]; + trx = (trx_t*) thd->ha_data[hton->slot]; if (trx) { innobase_release_stat_resources(trx); @@ -844,13 +851,14 @@ trx_t* check_trx_exists( /*=============*/ /* out: InnoDB transaction handle */ + handlerton* hton, /* in: handlerton for innodb */ THD* thd) /* in: user thread handle */ { trx_t* trx; ut_ad(thd == current_thd); - trx = (trx_t*) thd->ha_data[innobase_hton->slot]; + trx = (trx_t*) thd->ha_data[hton->slot]; if (trx == NULL) { DBUG_ASSERT(thd != NULL); @@ -864,7 +872,7 @@ check_trx_exists( CPU time */ trx->support_xa = (ibool)(thd->variables.innodb_support_xa); - thd->ha_data[innobase_hton->slot] = trx; + thd->ha_data[hton->slot] = trx; } else { if (trx->magic_n != TRX_MAGIC_N) { mem_analyze_corruption(trx); @@ -893,7 +901,7 @@ check_trx_exists( Construct ha_innobase handler. */ ha_innobase::ha_innobase(handlerton *hton, TABLE_SHARE *table_arg) - :handler(innobase_hton, table_arg), + :handler(hton, table_arg), int_table_flags(HA_REC_NOT_IN_SEQ | HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | @@ -920,7 +928,7 @@ ha_innobase::update_thd( row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; trx_t* trx; - trx = check_trx_exists(thd); + trx = check_trx_exists(ht, thd); if (prebuilt->trx != trx) { @@ -941,10 +949,11 @@ inline void innobase_register_stmt( /*===================*/ + handlerton* hton, /* in: Innobase hton */ THD* thd) /* in: MySQL thd (connection) object */ { /* Register the statement */ - trans_register_ha(thd, FALSE, innobase_hton); + trans_register_ha(thd, FALSE, hton); } /************************************************************************* @@ -958,17 +967,18 @@ inline void innobase_register_trx_and_stmt( /*===========================*/ + handlerton *hton, /* in: Innobase handlerton */ THD* thd) /* in: MySQL thd (connection) object */ { /* NOTE that actually innobase_register_stmt() registers also the transaction in the AUTOCOMMIT=1 mode. */ - innobase_register_stmt(thd); + innobase_register_stmt(hton, thd); if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { /* No autocommit mode, register for a transaction */ - trans_register_ha(thd, TRUE, innobase_hton); + trans_register_ha(thd, TRUE, hton); } } @@ -1064,7 +1074,7 @@ innobase_query_caching_of_table_permitted( return((my_bool)FALSE); } - trx = check_trx_exists(thd); + trx = check_trx_exists(legacy_innodb_hton, thd); if (trx->has_search_latch) { ut_print_timestamp(stderr); sql_print_error("The calling thread is holding the adaptive " @@ -1123,7 +1133,7 @@ innobase_query_caching_of_table_permitted( if (trx->active_trans == 0) { - innobase_register_trx_and_stmt(thd); + innobase_register_trx_and_stmt(legacy_innodb_hton, thd); trx->active_trans = 1; } @@ -1298,7 +1308,7 @@ ha_innobase::init_table_handle_for_HANDLER(void) if (prebuilt->trx->active_trans == 0) { - innobase_register_trx_and_stmt(current_thd); + innobase_register_trx_and_stmt(ht, current_thd); prebuilt->trx->active_trans = 1; } @@ -1341,7 +1351,8 @@ innobase_init(void *p) char *default_path; DBUG_ENTER("innobase_init"); - innobase_hton= (handlerton *)p; + handlerton *innobase_hton= (handlerton *)p; + legacy_innodb_hton= innobase_hton; innobase_hton->state=have_innodb; innobase_hton->db_type= DB_TYPE_INNODB; @@ -1616,7 +1627,7 @@ error: Closes an InnoDB database. */ int -innobase_end(ha_panic_function type) +innobase_end(handlerton *hton, ha_panic_function type) /*==============*/ /* out: TRUE if error */ { @@ -1654,7 +1665,7 @@ Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes the logs, and the name of this function should be innobase_checkpoint. */ bool -innobase_flush_logs(void) +innobase_flush_logs(handlerton *hton) /*=====================*/ /* out: TRUE if error */ { @@ -1693,6 +1704,7 @@ int innobase_start_trx_and_assign_read_view( /*====================================*/ /* out: 0 */ + handlerton *hton, /* in: Innodb handlerton */ THD* thd) /* in: MySQL thread handle of the user for whom the transaction should be committed */ { @@ -1702,7 +1714,7 @@ innobase_start_trx_and_assign_read_view( /* Create a new trx struct for thd, if it does not yet have one */ - trx = check_trx_exists(thd); + trx = check_trx_exists(hton, thd); /* This is just to play safe: release a possible FIFO ticket and search latch. Since we will reserve the kernel mutex, we have to @@ -1721,9 +1733,7 @@ innobase_start_trx_and_assign_read_view( /* Set the MySQL flag to mark that there is an active transaction */ if (trx->active_trans == 0) { - - innobase_register_trx_and_stmt(current_thd); - + innobase_register_trx_and_stmt(hton, current_thd); trx->active_trans = 1; } @@ -1738,7 +1748,8 @@ int innobase_commit( /*============*/ /* out: 0 */ - THD* thd, /* in: MySQL thread handle of the user for whom + handlerton *hton, /* in: Innodb handlerton */ + THD* thd, /* in: MySQL thread handle of the user for whom the transaction should be committed */ bool all) /* in: TRUE - commit transaction FALSE - the current SQL statement ended */ @@ -1748,7 +1759,7 @@ innobase_commit( DBUG_ENTER("innobase_commit"); DBUG_PRINT("trans", ("ending transaction")); - trx = check_trx_exists(thd); + trx = check_trx_exists(hton, thd); /* Update the info whether we should skip XA steps that eat CPU time */ trx->support_xa = (ibool)(thd->variables.innodb_support_xa); @@ -1874,6 +1885,7 @@ int innobase_report_binlog_offset_and_commit( /*=====================================*/ /* out: 0 */ + handlerton *hton, /* in: Innodb handlerton */ THD* thd, /* in: user thread */ void* trx_handle, /* in: InnoDB trx handle */ char* log_file_name, /* in: latest binlog file name */ @@ -1891,7 +1903,7 @@ innobase_report_binlog_offset_and_commit( trx->flush_log_later = TRUE; - innobase_commit(thd, TRUE); + innobase_commit(hton, thd, TRUE); trx->flush_log_later = FALSE; @@ -1939,11 +1951,12 @@ int innobase_commit_complete( /*=====================*/ /* out: 0 */ + handlerton *hton, /* in: Innodb handlerton */ THD* thd) /* in: user thread */ { trx_t* trx; - trx = (trx_t*) thd->ha_data[innobase_hton->slot]; + trx = (trx_t*) thd->ha_data[hton->slot]; if (trx && trx->active_trans) { @@ -1967,6 +1980,7 @@ static int innobase_rollback( /*==============*/ /* out: 0 or error number */ + handlerton *hton, /* in: Innodb handlerton */ THD* thd, /* in: handle to the MySQL thread of the user whose transaction should be rolled back */ bool all) /* in: TRUE - commit transaction @@ -1978,7 +1992,7 @@ innobase_rollback( DBUG_ENTER("innobase_rollback"); DBUG_PRINT("trans", ("aborting transaction")); - trx = check_trx_exists(thd); + trx = check_trx_exists(hton, thd); /* Update the info whether we should skip XA steps that eat CPU time */ trx->support_xa = (ibool)(thd->variables.innodb_support_xa); @@ -2050,6 +2064,7 @@ innobase_rollback_to_savepoint( /*===========================*/ /* out: 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the given name */ + handlerton *hton, /* in: Innodb handlerton */ THD* thd, /* in: handle to the MySQL thread of the user whose transaction should be rolled back */ void* savepoint) /* in: savepoint data */ @@ -2061,7 +2076,7 @@ innobase_rollback_to_savepoint( DBUG_ENTER("innobase_rollback_to_savepoint"); - trx = check_trx_exists(thd); + trx = check_trx_exists(hton, thd); /* Release a possible FIFO ticket and search latch. Since we will reserve the kernel mutex, we have to release the search system latch @@ -2086,6 +2101,7 @@ innobase_release_savepoint( /*=======================*/ /* out: 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the given name */ + handlerton* hton, /* in: handlerton for Innodb */ THD* thd, /* in: handle to the MySQL thread of the user whose transaction should be rolled back */ void* savepoint) /* in: savepoint data */ @@ -2096,7 +2112,7 @@ innobase_release_savepoint( DBUG_ENTER("innobase_release_savepoint"); - trx = check_trx_exists(thd); + trx = check_trx_exists(hton, thd); /* TODO: use provided savepoint data area to store savepoint data */ @@ -2114,6 +2130,7 @@ int innobase_savepoint( /*===============*/ /* out: always 0, that is, always succeeds */ + handlerton* hton, /* in: handle to the Innodb handlerton */ THD* thd, /* in: handle to the MySQL thread */ void* savepoint) /* in: savepoint data */ { @@ -2130,7 +2147,7 @@ innobase_savepoint( DBUG_ASSERT(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) || thd->in_sub_stmt); - trx = check_trx_exists(thd); + trx = check_trx_exists(hton, thd); /* Release a possible FIFO ticket and search latch. Since we will reserve the kernel mutex, we have to release the search system latch @@ -2157,12 +2174,13 @@ int innobase_close_connection( /*======================*/ /* out: 0 or error number */ + handlerton* hton, /* in: innobase handlerton */ THD* thd) /* in: handle to the MySQL thread of the user whose resources should be free'd */ { trx_t* trx; - trx = (trx_t*)thd->ha_data[innobase_hton->slot]; + trx = (trx_t*)thd->ha_data[hton->slot]; ut_a(trx); @@ -3255,11 +3273,11 @@ ha_innobase::write_row( DBUG_ENTER("ha_innobase::write_row"); if (prebuilt->trx != - (trx_t*) current_thd->ha_data[innobase_hton->slot]) { + (trx_t*) current_thd->ha_data[ht->slot]) { sql_print_error("The transaction object for the table handle is at " "%p, but for the current thread it is at %p", prebuilt->trx, - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr); ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200); @@ -3267,7 +3285,7 @@ ha_innobase::write_row( "InnoDB: Dump of 200 bytes around transaction.all: ", stderr); ut_print_buf(stderr, - ((byte*)(&(current_thd->ha_data[innobase_hton->slot]))) - 100, + ((byte*)(&(current_thd->ha_data[ht->slot]))) - 100, 200); putc('\n', stderr); ut_error; @@ -3321,7 +3339,7 @@ no_commit: no need to re-acquire locks on it. */ /* Altering to InnoDB format */ - innobase_commit(user_thd, 1); + innobase_commit(ht, user_thd, 1); /* Note that this transaction is still active. */ prebuilt->trx->active_trans = 1; /* We will need an IX lock on the destination table. */ @@ -3337,7 +3355,7 @@ no_commit: /* Commit the transaction. This will release the table locks, so they have to be acquired again. */ - innobase_commit(user_thd, 1); + innobase_commit(ht, user_thd, 1); /* Note that this transaction is still active. */ prebuilt->trx->active_trans = 1; /* Re-acquire the table lock on the source table. */ @@ -3640,7 +3658,7 @@ ha_innobase::update_row( DBUG_ENTER("ha_innobase::update_row"); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) table->timestamp_field->set_time(); @@ -3701,7 +3719,7 @@ ha_innobase::delete_row( DBUG_ENTER("ha_innobase::delete_row"); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); if (last_query_id != user_thd->query_id) { prebuilt->sql_stat_start = TRUE; @@ -3799,7 +3817,7 @@ ha_innobase::try_semi_consistent_read(bool yes) row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); /* Row read type is set to semi consistent read if this was requested by the MySQL and either innodb_locks_unsafe_for_binlog @@ -3966,7 +3984,7 @@ ha_innobase::index_read( DBUG_ENTER("index_read"); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status); @@ -4081,7 +4099,7 @@ ha_innobase::change_active_index( ut_ad(user_thd == current_thd); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); active_index = keynr; @@ -4171,7 +4189,7 @@ ha_innobase::general_fetch( DBUG_ENTER("general_fetch"); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); innodb_srv_conc_enter_innodb(prebuilt->trx); @@ -4407,7 +4425,7 @@ ha_innobase::rnd_pos( &LOCK_status); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); if (prebuilt->clust_index_was_generated) { /* No primary key was defined for the table and we @@ -4457,7 +4475,7 @@ ha_innobase::position( uint len; ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); if (prebuilt->clust_index_was_generated) { /* No primary key was defined for the table and we @@ -4785,7 +4803,7 @@ ha_innobase::create( /* Get the transaction associated with the current thd, or create one if not yet created */ - parent_trx = check_trx_exists(thd); + parent_trx = check_trx_exists(ht, thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ @@ -4958,7 +4976,7 @@ ha_innobase::discard_or_import_tablespace( ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); dict_table = prebuilt->table; trx = prebuilt->trx; @@ -5038,7 +5056,7 @@ ha_innobase::delete_table( /* Get the transaction associated with the current thd, or create one if not yet created */ - parent_trx = check_trx_exists(thd); + parent_trx = check_trx_exists(ht, thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ @@ -5105,6 +5123,7 @@ void innobase_drop_database( /*===================*/ /* out: error number */ + handlerton *hton, /* in: handlerton of Innodb */ char* path) /* in: database path; inside InnoDB the name of the last directory in the path is used as the database name: for example, in 'mysql/data/test' @@ -5120,7 +5139,7 @@ innobase_drop_database( /* Get the transaction associated with the current thd, or create one if not yet created */ - parent_trx = check_trx_exists(current_thd); + parent_trx = check_trx_exists(hton, current_thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ @@ -5199,7 +5218,7 @@ ha_innobase::rename_table( /* Get the transaction associated with the current thd, or create one if not yet created */ - parent_trx = check_trx_exists(current_thd); + parent_trx = check_trx_exists(ht, current_thd); /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ @@ -5286,7 +5305,7 @@ ha_innobase::records_in_range( DBUG_ENTER("records_in_range"); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); prebuilt->trx->op_info = (char*)"estimating records in index range"; @@ -5728,7 +5747,7 @@ ha_innobase::check( ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); if (prebuilt->mysql_template == NULL) { /* Build the template; we will use a dummy template @@ -6012,7 +6031,7 @@ ha_innobase::can_switch_engines(void) DBUG_ENTER("ha_innobase::can_switch_engines"); ut_a(prebuilt->trx == - (trx_t*) current_thd->ha_data[innobase_hton->slot]); + (trx_t*) current_thd->ha_data[ht->slot]); prebuilt->trx->op_info = "determining if there are foreign key constraints"; @@ -6205,10 +6224,10 @@ ha_innobase::start_stmt( /* Set the MySQL flag to mark that there is an active transaction */ if (trx->active_trans == 0) { - innobase_register_trx_and_stmt(thd); + innobase_register_trx_and_stmt(ht, thd); trx->active_trans = 1; } else { - innobase_register_stmt(thd); + innobase_register_stmt(ht, thd); } return(0); @@ -6281,10 +6300,10 @@ ha_innobase::external_lock( transaction */ if (trx->active_trans == 0) { - innobase_register_trx_and_stmt(thd); + innobase_register_trx_and_stmt(ht, thd); trx->active_trans = 1; } else if (trx->n_mysql_tables_in_use == 0) { - innobase_register_stmt(thd); + innobase_register_stmt(ht, thd); } trx->n_mysql_tables_in_use++; @@ -6362,7 +6381,7 @@ ha_innobase::external_lock( if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { if (trx->active_trans != 0) { - innobase_commit(thd, TRUE); + innobase_commit(ht, thd, TRUE); } } else { if (trx->isolation_level <= TRX_ISO_READ_COMMITTED @@ -6443,7 +6462,7 @@ ha_innobase::transactional_table_lock( /* Set the MySQL flag to mark that there is an active transaction */ if (trx->active_trans == 0) { - innobase_register_trx_and_stmt(thd); + innobase_register_trx_and_stmt(ht, thd); trx->active_trans = 1; } @@ -6491,6 +6510,7 @@ Monitor to the client. */ bool innodb_show_status( /*===============*/ + handlerton* hton, /* in: the innodb handlerton */ THD* thd, /* in: the MySQL query thread of the caller */ stat_print_fn *stat_print) { @@ -6506,7 +6526,7 @@ innodb_show_status( DBUG_RETURN(FALSE); } - trx = check_trx_exists(thd); + trx = check_trx_exists(hton, thd); innobase_release_stat_resources(trx); @@ -6581,6 +6601,7 @@ Implements the SHOW MUTEX STATUS command. . */ bool innodb_mutex_show_status( /*=====================*/ + handlerton* hton, /* in: the innodb handlerton */ THD* thd, /* in: the MySQL query thread of the caller */ stat_print_fn* stat_print) @@ -6662,14 +6683,15 @@ innodb_mutex_show_status( DBUG_RETURN(FALSE); } -bool innobase_show_status(THD* thd, stat_print_fn* stat_print, - enum ha_stat_type stat_type) +bool innobase_show_status(handlerton *hton, THD* thd, + stat_print_fn* stat_print, + enum ha_stat_type stat_type) { switch (stat_type) { case HA_ENGINE_STATUS: - return innodb_show_status(thd, stat_print); + return innodb_show_status(hton, thd, stat_print); case HA_ENGINE_MUTEX: - return innodb_mutex_show_status(thd, stat_print); + return innodb_mutex_show_status(hton, thd, stat_print); default: return FALSE; } @@ -6769,7 +6791,7 @@ ha_innobase::store_lock( because we call update_thd() later, in ::external_lock()! Failure to understand this caused a serious memory corruption bug in 5.1.11. */ - trx = check_trx_exists(thd); + trx = check_trx_exists(ht, thd); /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE! Be careful to ignore TL_IGNORE if we are going to do something with @@ -7155,7 +7177,7 @@ ha_innobase::reset_auto_increment(ulonglong value) bool ha_innobase::get_error_message(int error, String *buf) { - trx_t* trx = check_trx_exists(current_thd); + trx_t* trx = check_trx_exists(ht, current_thd); buf->copy(trx->detailed_error, strlen(trx->detailed_error), system_charset_info); @@ -7374,13 +7396,14 @@ int innobase_xa_prepare( /*================*/ /* out: 0 or error number */ + handlerton *hton, THD* thd, /* in: handle to the MySQL thread of the user whose XA transaction should be prepared */ bool all) /* in: TRUE - commit transaction FALSE - the current SQL statement ended */ { int error = 0; - trx_t* trx = check_trx_exists(thd); + trx_t* trx = check_trx_exists(hton, thd); if (thd->lex->sql_command != SQLCOM_XA_PREPARE && (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) @@ -7470,6 +7493,7 @@ innobase_xa_recover( /*================*/ /* out: number of prepared transactions stored in xid_list */ + handlerton *hton, XID* xid_list, /* in/out: prepared transactions */ uint len) /* in: number of slots in xid_list */ { @@ -7489,6 +7513,7 @@ int innobase_commit_by_xid( /*===================*/ /* out: 0 or error number */ + handlerton *hton, XID* xid) /* in: X/Open XA transaction identification */ { trx_t* trx; @@ -7512,6 +7537,7 @@ int innobase_rollback_by_xid( /*=====================*/ /* out: 0 or error number */ + handlerton *hton, XID *xid) /* in: X/Open XA transaction identification */ { trx_t* trx; @@ -7532,12 +7558,13 @@ This consistent view is then used inside of MySQL when accessing records using a cursor. */ void* -innobase_create_cursor_view(void) +innobase_create_cursor_view( /*=============================*/ /* out: Pointer to cursor view or NULL */ + handlerton *hton) /* in: innobase hton */ { return(read_cursor_view_create_for_mysql( - check_trx_exists(current_thd))); + check_trx_exists(hton, current_thd))); } /*********************************************************************** @@ -7548,9 +7575,10 @@ corresponding MySQL thread still lacks one. */ void innobase_close_cursor_view( /*=======================*/ + handlerton *hton, void* curview)/* in: Consistent read view to be closed */ { - read_cursor_view_close_for_mysql(check_trx_exists(current_thd), + read_cursor_view_close_for_mysql(check_trx_exists(hton, current_thd), (cursor_view_t*) curview); } @@ -7563,9 +7591,10 @@ restored to a transaction read view. */ void innobase_set_cursor_view( /*=====================*/ + handlerton *hton, void* curview)/* in: Consistent cursor view to be set */ { - read_cursor_set_for_mysql(check_trx_exists(current_thd), + read_cursor_set_for_mysql(check_trx_exists(hton, current_thd), (cursor_view_t*) curview); } diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index d87d9111139..7fd94c482d9 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -240,8 +240,8 @@ extern ulong srv_flush_log_at_trx_commit; } int innobase_init(void); -int innobase_end(ha_panic_function type); -bool innobase_flush_logs(void); +int innobase_end(handlerton *hton, ha_panic_function type); +bool innobase_flush_logs(handlerton *hton); uint innobase_get_free_space(void); /* @@ -258,14 +258,14 @@ int innobase_commit_complete(void* trx_handle); void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset); #endif -void innobase_drop_database(char *path); -bool innobase_show_status(THD* thd, stat_print_fn*, enum ha_stat_type); +void innobase_drop_database(handlerton *hton, char *path); +bool innobase_show_status(handlerton *hton, THD* thd, stat_print_fn*, enum ha_stat_type); -int innobase_release_temporary_latches(THD *thd); +int innobase_release_temporary_latches(handlerton *hton, THD *thd); -void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset); +void innobase_store_binlog_offset_and_flush_log(handlerton *hton, char *binlog_name,longlong offset); -int innobase_start_trx_and_assign_read_view(THD* thd); +int innobase_start_trx_and_assign_read_view(handlerton *hton, THD* thd); /*********************************************************************** This function is used to prepare X/Open XA distributed transaction */ @@ -273,6 +273,7 @@ This function is used to prepare X/Open XA distributed transaction */ int innobase_xa_prepare( /*====================*/ /* out: 0 or error number */ + handlerton *hton, /* in: innobase hton */ THD* thd, /* in: handle to the MySQL thread of the user whose XA transaction should be prepared */ bool all); /* in: TRUE - commit transaction @@ -285,6 +286,7 @@ int innobase_xa_recover( /*====================*/ /* out: number of prepared transactions stored in xid_list */ + handlerton *hton, /* in: innobase hton */ XID* xid_list, /* in/out: prepared transactions */ uint len); /* in: number of slots in xid_list */ @@ -295,6 +297,7 @@ which is in the prepared state */ int innobase_commit_by_xid( /*=======================*/ /* out: 0 or error number */ + handlerton *hton, /* in: innobase hton */ XID* xid); /* in : X/Open XA Transaction Identification */ /*********************************************************************** @@ -303,6 +306,7 @@ which is in the prepared state */ int innobase_rollback_by_xid( /* out: 0 or error number */ + handlerton *hton, /* in: innobase hton */ XID *xid); /* in : X/Open XA Transaction Identification */ @@ -313,9 +317,10 @@ This consistent view is then used inside of MySQL when accessing records using a cursor. */ void* -innobase_create_cursor_view(void); +innobase_create_cursor_view( /*=============================*/ /* out: Pointer to cursor view or NULL */ + handlerton *hton); /* in: innobase hton */ /*********************************************************************** Close the given consistent cursor view of a transaction and restore @@ -325,6 +330,7 @@ corresponding MySQL thread still lacks one. */ void innobase_close_cursor_view( /*=======================*/ + handlerton *hton, /* in: innobase hton */ void* curview); /* in: Consistent read view to be closed */ /*********************************************************************** @@ -336,4 +342,5 @@ restored to a transaction read view. */ void innobase_set_cursor_view( /*=====================*/ + handlerton *hton, /* in: innobase hton */ void* curview); /* in: Consistent read view to be set */ diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index ae4dcfc3f8b..c956190a56a 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1789,16 +1789,23 @@ bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info, return COMPATIBLE_DATA_YES; } -handlerton *myisam_hton; +extern int mi_panic(enum ha_panic_function flag); +int myisam_panic(handlerton *hton, ha_panic_function flag) +{ + return mi_panic(flag); +} static int myisam_init(void *p) { + handlerton *myisam_hton; + myisam_hton= (handlerton *)p; myisam_hton->state= SHOW_OPTION_YES; myisam_hton->db_type= DB_TYPE_MYISAM; myisam_hton->create= myisam_create_handler; - myisam_hton->panic= mi_panic; + myisam_hton->panic= myisam_panic; myisam_hton->flags= HTON_CAN_RECREATE; + return 0; } diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 54e5da320b5..7f656c2e67c 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -34,10 +34,6 @@ static handler *myisammrg_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root); -/* MyISAM MERGE handlerton */ - -handlerton *myisammrg_hton; - static handler *myisammrg_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) @@ -555,15 +551,23 @@ bool ha_myisammrg::check_if_incompatible_data(HA_CREATE_INFO *info, return COMPATIBLE_DATA_NO; } +extern int myrg_panic(enum ha_panic_function flag); +int myisammrg_panic(handlerton *hton, ha_panic_function flag) +{ + return myrg_panic(flag); +} + static int myisammrg_init(void *p) { + handlerton *myisammrg_hton; + myisammrg_hton= (handlerton *)p; - myisammrg_hton->state=have_merge_db; - myisammrg_hton->db_type=DB_TYPE_MRG_MYISAM; - myisammrg_hton->create=myisammrg_create_handler; - myisammrg_hton->panic=myrg_panic; - myisammrg_hton->flags= HTON_CAN_RECREATE; + myisammrg_hton->state= have_merge_db; + myisammrg_hton->db_type= DB_TYPE_MRG_MYISAM; + myisammrg_hton->create= myisammrg_create_handler; + myisammrg_hton->panic= myisammrg_panic; + myisammrg_hton->flags= HTON_CAN_RECREATE|HTON_NO_PARTITION; return 0; } From 56505c01f911d788edc13f099ac99193b92a26c6 Mon Sep 17 00:00:00 2001 From: "brian@zim.(none)" <> Date: Sat, 30 Sep 2006 18:31:13 -0700 Subject: [PATCH 26/28] This patch updates to remove most global hton needs. Cleans up wrong message in partition. --- mysql-test/r/partition.result | 6 +++--- sql/ha_ndbcluster.cc | 2 +- sql/ha_partition.cc | 2 +- sql/handler.cc | 8 +++----- sql/mysql_priv.h | 4 ---- sql/mysqld.cc | 3 +-- sql/partition_info.cc | 3 +-- sql/share/errmsg.txt | 6 +++--- sql/sql_cache.cc | 4 ++-- 9 files changed, 15 insertions(+), 23 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index d8d433ef216..6c37f0834e9 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -68,7 +68,7 @@ create table t1 (a int) engine = csv partition by list (a) (partition p0 values in (null)); -ERROR HY000: CSV handler cannot be used in partitioned tables +ERROR HY000: Engine cannot be used in partitioned tables create table t1 (a bigint) partition by range (a) (partition p0 values less than (0xFFFFFFFFFFFFFFFF), @@ -102,7 +102,7 @@ create table t1 (a int) engine = csv partition by list (a) (partition p0 values in (null)); -ERROR HY000: CSV handler cannot be used in partitioned tables +ERROR HY000: Engine cannot be used in partitioned tables create table t1 (a int) partition by key(a) (partition p0 engine = MEMORY); @@ -1054,7 +1054,7 @@ drop table t1; create table t1 (a int) partition by key (a) (partition p0 engine = MERGE); -ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables +ERROR HY000: Engine cannot be used in partitioned tables create table t1 (a varchar(1)) partition by key (a) as select 'a'; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0d57f3decec..fffa87daf64 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -87,7 +87,7 @@ static int ndbcluster_fill_files_table(handlerton *hton, TABLE_LIST *tables, COND *cond); -handlerton *ndbcluster_hton; +static handlerton *ndbcluster_hton; static handler *ndbcluster_create_handler(handlerton *hton, TABLE_SHARE *table, diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d2b05df5ffc..0da0094d92e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -75,11 +75,11 @@ static handler *partition_create_handler(handlerton *hton, static uint partition_flags(); static uint alter_table_flags(uint flags); -handlerton *partition_hton; static int partition_initialize(void *p) { + handlerton *partition_hton; partition_hton= (handlerton *)p; partition_hton->state= SHOW_OPTION_YES; diff --git a/sql/handler.cc b/sql/handler.cc index bbb2cab5af2..ccf1a1ef8d9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -467,13 +467,11 @@ int ha_initialize_handlerton(st_plugin_int *plugin) } /* - This is entirely for legacy. We will create a new "disk based" hton and a "memory" hton - which will be configurable longterm. + This is entirely for legacy. We will create a new "disk based" hton and a + "memory" hton which will be configurable longterm. We should be able to + remove partition and myisammrg. */ switch (hton->db_type) { - case DB_TYPE_MRG_ISAM: - myisammrg_hton= hton; - break; case DB_TYPE_HEAP: heap_hton= hton; break; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9cd8e36c996..0a858246420 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1638,11 +1638,7 @@ extern SHOW_COMP_OPTION have_ndbcluster; extern SHOW_COMP_OPTION have_partition_db; extern SHOW_COMP_OPTION have_merge_db; -#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE -extern handlerton *ndbcluster_hton; -#endif extern handlerton *partition_hton; -extern handlerton *myisammrg_hton; extern handlerton *myisam_hton; extern handlerton *heap_hton; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d820e2f4192..ba7db6aaf82 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -358,10 +358,9 @@ my_bool opt_innodb; /* Legacy global handlerton. These will be removed (please do not add more). */ -handlerton *ndbclusert_hton; -handlerton *myisammrg_hton; handlerton *heap_hton; handlerton *myisam_hton; +handlerton *partition_hton; #ifdef WITH_INNOBASE_STORAGE_ENGINE extern ulong innobase_fast_shutdown; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3210eb0675e..b3c7c1b80e7 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -445,8 +445,7 @@ bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts) } while (++i < no_parts); if (engine_array[0]->flags & HTON_NO_PARTITION) { - my_error(ER_PARTITION_MERGE_ERROR, MYF(0), - engine_array[0] == myisammrg_hton ? "MyISAM Merge" : "CSV"); + my_error(ER_PARTITION_MERGE_ERROR, MYF(0)); DBUG_RETURN(TRUE); } DBUG_RETURN(FALSE); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index ccbdd3586a2..1d0e9e9ab79 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5960,9 +5960,9 @@ ER_EVENT_SET_VAR_ERROR eng "Error during starting/stopping of the scheduler. Error code %u" ger "Fehler während des Startens oder Anhalten des Schedulers. Fehlercode %u" ER_PARTITION_MERGE_ERROR - eng "%s handler cannot be used in partitioned tables" - ger "%s-Handler kann in partitionierten Tabellen nicht verwendet werden" - swe "%s kan inte användas i en partitionerad tabell" + eng "Engine cannot be used in partitioned tables" + ger "Engine kann in partitionierten Tabellen nicht verwendet werden" + swe "Engine inte användas i en partitionerad tabell" ER_CANT_ACTIVATE_LOG eng "Cannot activate '%-.64s' log" ger "Kann Logdatei '%-.64s' nicht aktivieren" diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index e0831b0f8ee..ee3b8aa79fe 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2389,7 +2389,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, tables_used->engine_data)) DBUG_RETURN(0); - if (tables_used->table->s->db_type == myisammrg_hton) + if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM) { ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file; MYRG_INFO *file = handler->myrg_info(); @@ -3013,7 +3013,7 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used, "other non-cacheable table(s)")); DBUG_RETURN(0); } - if (tables_used->table->s->db_type == myisammrg_hton) + if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM) { ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file; MYRG_INFO *file = handler->myrg_info(); From fc0fa8da3f5cbcd3fb675819a09edb9588fc9efb Mon Sep 17 00:00:00 2001 From: "brian@zim.(none)" <> Date: Sat, 30 Sep 2006 19:08:13 -0700 Subject: [PATCH 27/28] Merge fix. --- sql/sql_cursor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index a9ad35e7f9b..46fae3ffb99 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -433,7 +433,7 @@ Sensitive_cursor::fetch(ulong num_rows) thd->set_n_backup_active_arena(this, &backup_arena); for (info= ht_info; info->read_view ; info++) - (info->ht->set_cursor_read_view)(info->htthd, info->read_view); + (info->ht->set_cursor_read_view)(info->ht, thd, info->read_view); join->fetch_limit+= num_rows; From 8685747f066728449f276b391e27688ee8d97ca4 Mon Sep 17 00:00:00 2001 From: "brian@zim.(none)" <> Date: Sun, 1 Oct 2006 11:17:59 -0700 Subject: [PATCH 28/28] This patch makes ndbcluster_hton not static. I have a second patch for ndbcluster_hton to be static, but I want to talk to Jonas first. --- sql/ha_ndbcluster.cc | 2 +- sql/ha_ndbcluster_binlog.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index fffa87daf64..0d57f3decec 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -87,7 +87,7 @@ static int ndbcluster_fill_files_table(handlerton *hton, TABLE_LIST *tables, COND *cond); -static handlerton *ndbcluster_hton; +handlerton *ndbcluster_hton; static handler *ndbcluster_create_handler(handlerton *hton, TABLE_SHARE *table, diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h index 822ebf3e358..233d1a58aaa 100644 --- a/sql/ha_ndbcluster_binlog.h +++ b/sql/ha_ndbcluster_binlog.h @@ -31,6 +31,8 @@ extern ulong ndb_extra_logging; #define NDB_INVALID_SCHEMA_OBJECT 241 +extern handlerton *ndbcluster_hton; + /* The numbers below must not change as they are passed between mysql servers, and if changed @@ -103,7 +105,6 @@ extern pthread_mutex_t injector_mutex; extern pthread_cond_t injector_cond; extern unsigned char g_node_id_map[max_ndb_nodes]; -extern handlerton *ndbcluster_hton; extern pthread_t ndb_util_thread; extern pthread_mutex_t LOCK_ndb_util_thread; extern pthread_cond_t COND_ndb_util_thread;