From 42d30b758baa6fd311e4982b2b79769996a8f0be Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 19 Aug 2004 00:29:11 +0200 Subject: [PATCH 01/13] Fix for BUG#4971 "CREATE TABLE ... TYPE=HEAP SELECT ... stops slave (wrong DELETE in binlog)": replacing the no_log argument of mysql_create_table() by some safer method (temporarily setting OPTION_BIN_LOG to 0) which guarantees that even the automatic DELETE FROM heap_table does not get into the binlog when a not-yet-existing HEAP table is opened by mysql_create_table(). --- mysql-test/r/rpl_heap.result | 12 ++++++------ mysql-test/t/rpl_heap.test | 6 ++++-- sql/log.cc | 16 ++++++++++++++++ sql/mysql_priv.h | 2 +- sql/sql_class.h | 21 +++++++++++++++++++++ sql/sql_parse.cc | 2 +- sql/sql_table.cc | 28 +++++++++++++++++++++------- 7 files changed, 70 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/rpl_heap.result b/mysql-test/r/rpl_heap.result index 1556bcd5f25..1facbcb7676 100644 --- a/mysql-test/r/rpl_heap.result +++ b/mysql-test/r/rpl_heap.result @@ -1,22 +1,22 @@ reset master; drop table if exists t1; -create table t1 (a int) type=HEAP; -insert into t1 values(10); +create table t1 type=HEAP select 10 as a; +insert into t1 values(11); show binlog events from 79; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.001 79 Query 1 79 use `test`; create table t1 (a int) type=HEAP -master-bin.001 147 Query 1 147 use `test`; DELETE FROM `test`.`t1` -master-bin.001 205 Query 1 205 use `test`; insert into t1 values(10) +master-bin.001 79 Query 1 79 use `test`; create table t1 type=HEAP select 10 as a +master-bin.001 154 Query 1 154 use `test`; insert into t1 values(11) reset slave; start slave; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` int(11) default NULL + `a` bigint(2) NOT NULL default '0' ) TYPE=HEAP select * from t1; a 10 +11 select * from t1; a select * from t1 limit 10; diff --git a/mysql-test/t/rpl_heap.test b/mysql-test/t/rpl_heap.test index 15f61918034..0bc71eaf30c 100644 --- a/mysql-test/t/rpl_heap.test +++ b/mysql-test/t/rpl_heap.test @@ -13,8 +13,10 @@ connect (slave,localhost,root,,test,0,slave.sock); connection master; reset master; drop table if exists t1; -create table t1 (a int) type=HEAP; -insert into t1 values(10); +# we use CREATE SELECT to verify that DELETE does not get into binlog +# before CREATE SELECT +create table t1 type=HEAP select 10 as a; +insert into t1 values(11); save_master_pos; show binlog events from 79; connection slave; diff --git a/sql/log.cc b/sql/log.cc index e031656cc6e..2956efc047f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1627,6 +1627,22 @@ void MYSQL_LOG::set_max_size(ulong max_size_arg) } +Disable_binlog::Disable_binlog(THD *thd_arg) : + thd(thd_arg), + save_options(thd_arg->options), save_master_access(thd_arg->master_access) +{ + thd_arg->options&= ~OPTION_BIN_LOG; + thd_arg->master_access|= SUPER_ACL; // unneeded in 4.1 +}; + + +Disable_binlog::~Disable_binlog() +{ + thd->options= save_options; + thd->master_access= save_master_access; +} + + /* Check if a string is a valid number diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2e893ead407..ca4b8d2c2b9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -438,7 +438,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, int mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List &fields, List &keys, - bool tmp_table, bool no_log); + bool tmp_table); TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, const char *db, const char *name, List *extra_fields, diff --git a/sql/sql_class.h b/sql/sql_class.h index e646d33fe5d..8284cd23b9e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -638,6 +638,27 @@ public: #define SYSTEM_THREAD_SLAVE_IO 2 #define SYSTEM_THREAD_SLAVE_SQL 4 +/* + Disables binary logging for one thread, and resets it back to what it was + before being disabled. + Some functions (like the internal mysql_create_table() when it's called by + mysql_alter_table()) must NOT write to the binlog (binlogging is done at the + at a later stage of the command already, and must be, for locking reasons); + so we internally disable it temporarily by creating the Disable_binlog + object and reset the state by destroying the object (don't forget that! or + write code so that the object gets automatically destroyed when leaving a + function...). +*/ +class Disable_binlog { +private: + THD *thd; + ulong save_options; + ulong save_master_access; +public: + Disable_binlog(THD *thd_arg); + ~Disable_binlog(); +}; + /* Used to hold information about file and file structure in exchainge via non-DB file (...INTO OUTFILE..., ...LOAD DATA...) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 39c1a78b081..7a5260a78f0 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1692,7 +1692,7 @@ mysql_execute_command(void) tables->real_name, &lex->create_info, lex->create_list, - lex->key_list,0, 0); // do logging + lex->key_list,0); if (!res) send_ok(&thd->net); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7f4a8583b78..c09892ac48b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -336,7 +336,6 @@ static int sort_keys(KEY *a, KEY *b) keys List of keys to create tmp_table Set to 1 if this is an internal temporary table (From ALTER TABLE) - no_log Don't log the query to binary log. DESCRIPTION If one creates a temporary table, this is automaticly opened @@ -354,7 +353,7 @@ static int sort_keys(KEY *a, KEY *b) int mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List &fields, - List &keys,bool tmp_table,bool no_log) + List &keys,bool tmp_table) { char path[FN_REFLEN]; const char *key_name, *alias; @@ -779,7 +778,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, goto end; } } - if (!tmp_table && !no_log) + if (!tmp_table) { // Must be written before unlock mysql_update_log.write(thd,thd->query, thd->query_length); @@ -843,6 +842,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, TABLE tmp_table; // Used during 'create_field()' TABLE *table; tmp_table.table_name=0; + Disable_binlog disable_binlog(thd); DBUG_ENTER("create_table_from_items"); /* Add selected items to field list */ @@ -873,9 +873,17 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } /* create and lock table */ /* QQ: This should be done atomic ! */ + /* We don't log the statement, it will be logged later */ if (mysql_create_table(thd,db,name,create_info,*extra_fields, - *keys,0,1)) // no logging + *keys,0)) DBUG_RETURN(0); + /* + If this is a HEAP table, the automatic DELETE FROM which is written to the + binlog when a HEAP table is opened for the first time since startup, must + not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we + don't want to delete from it) 2) it would be written before the CREATE + TABLE, which is a wrong order. So we keep binary logging disabled. + */ if (!(table=open_table(thd,db,name,name,(bool*) 0))) { quick_rm_table(create_info->db_type,db,table_case_name(create_info,name)); @@ -892,6 +900,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } table->file->extra(HA_EXTRA_WRITE_CACHE); DBUG_RETURN(table); + /* Note that leaving the function resets binlogging properties */ } @@ -1753,6 +1762,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, List_iterator key_it(keys); List_iterator field_it(create_list); List key_parts; + Disable_binlog *disable_binlog; KEY *key_info=table->key_info; for (uint i=0 ; i < table->keys ; i++,key_info++) @@ -1915,12 +1925,16 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } else create_info->data_file_name=create_info->index_file_name=0; - + /* We don't log the statement, it will be logged later */ + disable_binlog= new Disable_binlog(thd); if ((error=mysql_create_table(thd, new_db, tmp_name, create_info, - create_list,key_list,1,1))) // no logging + create_list,key_list,1))) + { + delete disable_binlog; DBUG_RETURN(error); - + } + delete disable_binlog; // reset binlogging properties for next code lines if (table->tmp_table) new_table=open_table(thd,new_db,tmp_name,tmp_name,0); else From 754fafd28f49160d3f514ef53a0181bf13ec4e0d Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 19 Aug 2004 02:35:59 +0200 Subject: [PATCH 02/13] copied new my_vsnprintf from 4.1. use "ul" when merging --- .bzrignore | 1 + mysys/my_vsnprintf.c | 92 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/.bzrignore b/.bzrignore index a7c02ee341b..8583b7ef437 100644 --- a/.bzrignore +++ b/.bzrignore @@ -544,3 +544,4 @@ vio/test-sslclient vio/test-sslserver vio/viotest-ssl scripts/make_win_binary_distribution +EXCEPTIONS-CLIENT diff --git a/mysys/my_vsnprintf.c b/mysys/my_vsnprintf.c index e49b1d0e729..289c21e1ea4 100644 --- a/mysys/my_vsnprintf.c +++ b/mysys/my_vsnprintf.c @@ -14,12 +14,24 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "mysys_priv.h" -#include "mysys_err.h" +#include #include #include #include -#include + +/* + Limited snprintf() implementations + + IMPLEMENTION: + Supports following formats: + %#[l]d + %#[l]u + %#[l]x + %#.#s Note first # is ignored + + RETURN + length of result string +*/ int my_snprintf(char* to, size_t n, const char* fmt, ...) { @@ -35,6 +47,8 @@ int my_snprintf(char* to, size_t n, const char* fmt, ...) int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap) { char *start=to, *end=to+n-1; + uint length, width, pre_zero, have_long; + for (; *fmt ; fmt++) { if (fmt[0] != '%') @@ -44,33 +58,77 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap) *to++= *fmt; /* Copy ordinary char */ continue; } - /* Skip if max size is used (to be compatible with printf) */ - fmt++; - while (isdigit(*fmt) || *fmt == '.' || *fmt == '-') + fmt++; /* skip '%' */ + /* Read max fill size (only used with %d and %u) */ + if (*fmt == '-') fmt++; + length= width= pre_zero= have_long= 0; + for (;isdigit(*fmt); fmt++) + { + length=length*10+ (uint) (*fmt-'0'); + if (!length) + pre_zero= 1; /* first digit was 0 */ + } + if (*fmt == '.') + for (fmt++;isdigit(*fmt); fmt++) + width=width*10+ (uint) (*fmt-'0'); + else + width= ~0; if (*fmt == 'l') + { fmt++; + have_long= 1; + } if (*fmt == 's') /* String parameter */ { reg2 char *par = va_arg(ap, char *); - uint plen,left_len = (uint)(end-to); + uint plen,left_len = (uint)(end-to)+1; if (!par) par = (char*)"(null)"; plen = (uint) strlen(par); + set_if_smaller(plen,width); if (left_len <= plen) plen = left_len - 1; to=strnmov(to,par,plen); continue; } - else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */ + else if (*fmt == 'd' || *fmt == 'u'|| *fmt== 'x') /* Integer parameter */ { - register int iarg; - if ((uint) (end-to) < 16) - break; - iarg = va_arg(ap, int); - if (*fmt == 'd') - to=int10_to_str((long) iarg,to, -10); + register long larg; + uint res_length, to_length; + char *store_start= to, *store_end; + char buff[32]; + + if ((to_length= (uint) (end-to)) < 16 || length) + store_start= buff; + if (have_long) + larg = va_arg(ap, long); else - to=int10_to_str((long) (uint) iarg,to,10); + if (*fmt == 'd') + larg = va_arg(ap, int); + else + larg= (long) (uint) va_arg(ap, int); + if (*fmt == 'd') + store_end= int10_to_str(larg, store_start, -10); + else + if (*fmt== 'u') + store_end= int10_to_str(larg, store_start, 10); + else + store_end= int2str(larg, store_start, 16); + if ((res_length= (uint) (store_end - store_start)) > to_length) + break; /* num doesn't fit in output */ + /* If %#d syntax was used, we have to pre-zero/pre-space the string */ + if (store_start == buff) + { + length= min(length, to_length); + if (res_length < length) + { + uint diff= (length- res_length); + bfill(to, diff, pre_zero ? '0' : ' '); + to+= diff; + } + bmove(to, store_start, res_length); + } + to+= res_length; continue; } /* We come here on '%%', unknown code or too long parameter */ @@ -78,7 +136,6 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap) break; *to++='%'; /* % used as % or unknown code */ } - DBUG_ASSERT(to <= end); *to='\0'; /* End of errmessage */ return (uint) (to - start); } @@ -96,7 +153,7 @@ static void my_printf(const char * fmt, ...) n = my_vsnprintf(buf, sizeof(buf)-1,fmt, ar); printf(buf); printf("n=%d, strlen=%d\n", n, strlen(buf)); - if (buf[sizeof(buf)-1] != OVERRUN_SENTRY) + if ((uchar) buf[sizeof(buf)-1] != OVERRUN_SENTRY) { fprintf(stderr, "Buffer overrun\n"); abort(); @@ -117,6 +174,7 @@ int main() my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack"); my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1); my_printf("Hello %u\n", 1); + my_printf("Hex: %lx '%6lx'\n", 32, 65); my_printf("conn %ld to: '%-.64s' user: '%-.32s' host:\ `%-.64s' (%-.64s)", 1, 0,0,0,0); return 0; From 71d6b352674da7bd1f584ed08c626af9e26aef8d Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 19 Aug 2004 09:02:29 +0200 Subject: [PATCH 03/13] dependencies are auto-generated --- sql/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/Makefile.am b/sql/Makefile.am index d1dfbfb390e..ec4e729bedb 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -45,7 +45,6 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \ @innodb_system_libs@ \ @ndbcluster_libs@ @ndbcluster_system_libs@ \ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@ -mysqld_DEPENDENCIES = @ndbcluster_libs@ @ndbcluster_system_libs@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ item_strfunc.h item_timefunc.h item_uniq.h \ item_create.h item_subselect.h item_row.h \ From 96a000ae78c006933cc964b34b66bfc3fc3ce8e5 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 19 Aug 2004 10:01:01 +0200 Subject: [PATCH 04/13] cosmetic change --- sql/sql_class.h | 2 +- sql/sql_table.cc | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 8284cd23b9e..3c968c6a8ae 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -647,7 +647,7 @@ public: so we internally disable it temporarily by creating the Disable_binlog object and reset the state by destroying the object (don't forget that! or write code so that the object gets automatically destroyed when leaving a - function...). + block, see example in sql_table.cc). */ class Disable_binlog { private: diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c09892ac48b..96eebd98ac3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1762,7 +1762,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, List_iterator key_it(keys); List_iterator field_it(create_list); List key_parts; - Disable_binlog *disable_binlog; KEY *key_info=table->key_info; for (uint i=0 ; i < table->keys ; i++,key_info++) @@ -1925,16 +1924,17 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } else create_info->data_file_name=create_info->index_file_name=0; - /* We don't log the statement, it will be logged later */ - disable_binlog= new Disable_binlog(thd); - if ((error=mysql_create_table(thd, new_db, tmp_name, - create_info, - create_list,key_list,1))) { - delete disable_binlog; - DBUG_RETURN(error); + /* + We don't log the statement, it will be logged later. Using a block so + that disable_binlog is deleted when we leave it in either way. + */ + Disable_binlog disable_binlog(thd); + if ((error=mysql_create_table(thd, new_db, tmp_name, + create_info, + create_list,key_list,1))) + DBUG_RETURN(error); } - delete disable_binlog; // reset binlogging properties for next code lines if (table->tmp_table) new_table=open_table(thd,new_db,tmp_name,tmp_name,0); else From 8ef3cdc2f93417d53a8a7df94ba879b6fdc7544f Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 19 Aug 2004 11:21:08 +0200 Subject: [PATCH 05/13] take dec. point into account in store_double_in_string --- sql/field.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 33717d99583..1b5c688fe7a 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3716,7 +3716,7 @@ static void store_double_in_string_field(Field_str *field, uint32 field_length, { bool use_scientific_notation=TRUE; char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; - int length; + uint length; if (field_length < 32 && nr > 1) { if (field->ceiling == 0) @@ -3732,11 +3732,17 @@ static void store_double_in_string_field(Field_str *field, uint32 field_length, } use_scientific_notation= (field->ceiling < nr); } - length= sprintf(buff, "%-.*g", - use_scientific_notation ? max(0,field_length-5) : field_length, - nr); - DBUG_ASSERT(length <= field_length); - field->store(buff, (uint) length); + length= (uint)sprintf(buff, "%-.*g", + use_scientific_notation ? max(0,field_length-5) : field_length, + nr); + /* + +1 below is because "precision" in %g above means the + max. number of significant digits, not the output width. + Thus the width can be larger than number of significant digits by 1 + (for decimal point) + */ + DBUG_ASSERT(length <= field_length+1); + field->store(buff, min(length, field_length)); } void Field_string::store(double nr) From dd3db08be3ffa7edb0bda4361acf89b57950a4fd Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 19 Aug 2004 13:07:54 +0200 Subject: [PATCH 06/13] typos fixed --- mysys/mf_tempfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysys/mf_tempfile.c b/mysys/mf_tempfile.c index ea2bec076d4..ca9912d9210 100644 --- a/mysys/mf_tempfile.c +++ b/mysys/mf_tempfile.c @@ -98,7 +98,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix, if (strlen(dir)+ pfx_len > FN_REFLEN-2) { errno=my_errno= ENAMETOOLONG; - return 1; + DBUG_RETURN(file); } strmov(convert_dirname(to,dir,NullS),prefix_buff); org_file=mkstemp(to); @@ -124,7 +124,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix, #ifdef OS2 /* changing environ variable doesn't work with VACPP */ char buffer[256], *end; - buffer[sizeof[buffer)-1]= 0; + buffer[sizeof(buffer)-1]= 0; end= strxnmov(buffer, sizeof(buffer)-1, (char*) "TMP=", dir, NullS); /* remove ending backslash */ if (end[-1] == '\\') From a29c9d37076bdc29e2870c15c4b43f3ab90f4618 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 19 Aug 2004 18:40:15 +0200 Subject: [PATCH 07/13] Bug #4769 - ft in subqueries --- mysql-test/r/subselect.result | 13 +++++++++++++ mysql-test/t/subselect.test | 13 +++++++++++++ sql/sql_select.cc | 10 ++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 77339473142..fe7ffa9b661 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1899,3 +1899,16 @@ select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL ( a C 1 1 drop table t1,t2; +create table t1 (a int not null auto_increment primary key, b varchar(40), fulltext(b)); +insert into t1 (b) values ('ball'),('ball games'), ('games'), ('foo'), ('foobar'), ('Serg'), ('Sergei'),('Georg'), ('Patrik'),('Hakan'); +create table t2 (a int); +insert into t2 values (1),(3),(2),(7); +select a,b from t1 where match(b) against ('Ball') > 0; +a b +1 ball +2 ball games +select a from t2 where a in (select a from t1 where match(b) against ('Ball') > 0); +a +1 +2 +drop table t1,t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index eb4b1f33b14..02a570b1db3 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1222,3 +1222,16 @@ CREATE TABLE `t2` ( `b` int(11) default NULL, `a` int(11) default NULL) ENGINE=M insert into t2 values (1,2); select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (SELECT count(*) FROM t2 t001 WHERE t001.a=1); drop table t1,t2; + +# +# BUG#4769 - fulltext in subselect +# +create table t1 (a int not null auto_increment primary key, b varchar(40), fulltext(b)); +insert into t1 (b) values ('ball'),('ball games'), ('games'), ('foo'), ('foobar'), ('Serg'), ('Sergei'),('Georg'), ('Patrik'),('Hakan'); +create table t2 (a int); +insert into t2 values (1),(3),(2),(7); +select a,b from t1 where match(b) against ('Ball') > 0; +select a from t2 where a in (select a from t1 where match(b) against ('Ball') > 0); +drop table t1,t2; + + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c56645e06b9..3a0ae219e81 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -729,6 +729,10 @@ JOIN::optimize() (select_lex->ftfunc_list->elements ? SELECT_NO_JOIN_CACHE : 0)); + /* Perform FULLTEXT search before all regular searches */ + if (!(select_options & SELECT_DESCRIBE)) + init_ftfuncs(thd, select_lex, test(order)); + /* is this simple IN subquery? */ @@ -784,7 +788,7 @@ JOIN::optimize() join_tab->info= "Using index; Using where"; else join_tab->info= "Using index"; - + DBUG_RETURN(unit->item-> change_engine(new subselect_indexsubquery_engine(thd, join_tab, @@ -849,8 +853,6 @@ JOIN::optimize() } having= 0; - /* Perform FULLTEXT search before all regular searches */ - init_ftfuncs(thd, select_lex, test(order)); /* Create a tmp table if distinct or if the sort is too complicated */ if (need_tmp) { @@ -858,7 +860,7 @@ JOIN::optimize() thd->proc_info="Creating tmp table"; init_items_ref_array(); - + tmp_table_param.hidden_field_count= (all_fields.elements - fields_list.elements); if (!(exec_tmp_table1 = From ad7f0fa51eee2460dd34893f6cba22420d5c047a Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Thu, 19 Aug 2004 21:41:10 +0200 Subject: [PATCH 08/13] Build bug on 64-Bit platforms. Removed improper casts. Thanks to Joerg Bruehe for the fix. --- include/my_global.h | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index 33ae35d2308..f24fc05471e 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -641,29 +641,17 @@ extern double my_atof(const char*); #endif #endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ -#if SIZEOF_LONG == 4 -#define INT_MIN32 ((long) 0x80000000L) -#define INT_MAX32 ((long) 0x7FFFFFFFL) -#define UINT_MAX32 ((long) 0xFFFFFFFFL) -#define INT_MIN24 ((long) 0xFF800000L) -#define INT_MAX24 0x007FFFFFL -#define UINT_MAX24 0x00FFFFFFL -#define INT_MIN16 ((short int) 0x8000) +#define INT_MIN32 (~0x7FFFFFFFL) +#define INT_MAX32 0x7FFFFFFFL +#define UINT_MAX32 0xFFFFFFFFL +#define INT_MIN24 (~0x007FFFFF) +#define INT_MAX24 0x007FFFFF +#define UINT_MAX24 0x00FFFFFF +#define INT_MIN16 (~0x7FFF) #define INT_MAX16 0x7FFF #define UINT_MAX16 0xFFFF -#define INT_MIN8 ((char) 0x80) -#define INT_MAX8 ((char) 0x7F) -#else /* Probably Alpha */ -#define INT_MIN32 ((long) (int) 0x80000000) -#define INT_MAX32 ((long) (int) 0x7FFFFFFF) -#define UINT_MAX32 ((long) (int) 0xFFFFFFFF) -#define INT_MIN24 ((long) (int) 0xFF800000) -#define INT_MAX24 ((long) (int) 0x007FFFFF) -#define UINT_MAX24 ((long) (int) 0x00FFFFFF) -#define INT_MIN16 ((short int) 0xFFFF8000) -#define INT_MAX16 ((short int) 0x00007FFF) -#define UINT_MAX16 ((short int) 0x0000FFFF) -#endif +#define INT_MIN8 (~0x7F) +#define INT_MAX8 0x7F /* From limits.h instead */ #ifndef DBL_MIN From 1773e759e4a6331af77170f73d95b562fed43deb Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Thu, 19 Aug 2004 23:22:16 +0300 Subject: [PATCH 09/13] ha_innodb.cc: innobase_mysql_tmpfile(): call dup() and my_close() on the file returned by create_temp_file() in order to avoid memory leak caused by my_open() being paired with close() --- sql/ha_innodb.cc | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 22ddfe779d5..3d3aca9cfd5 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -31,6 +31,7 @@ have disables the InnoDB inlining in this file. */ #include #include #include +#include #define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1)) @@ -419,6 +420,7 @@ innobase_mysql_tmpfile(void) /* out: temporary file descriptor, or < 0 on error */ { char filename[FN_REFLEN]; + int fd2 = -1; File fd = create_temp_file(filename, NullS, "ib", #ifdef __WIN__ O_BINARY | O_TRUNC | O_SEQUENTIAL | @@ -426,12 +428,31 @@ innobase_mysql_tmpfile(void) #endif /* __WIN__ */ O_CREAT | O_EXCL | O_RDWR, MYF(MY_WME)); -#ifndef __WIN__ if (fd >= 0) { +#ifndef __WIN__ + /* On Windows, open files cannot be removed, but files can be + created with the O_TEMPORARY flag to the same effect + ("delete on close"). */ unlink(filename); - } #endif /* !__WIN__ */ - return(fd); + /* Copy the file descriptor, so that the additional resources + allocated by create_temp_file() can be freed by invoking + my_close(). + + Because the file descriptor returned by this function + will be passed to fdopen(), it will be closed by invoking + fclose(), which in turn will invoke close() instead of + my_close(). */ + fd2 = dup(fd); + if (fd2 < 0) { + DBUG_PRINT("error",("Got error %d on dup",fd2)); + my_errno=errno; + my_error(EE_OUT_OF_FILERESOURCES, + MYF(ME_BELL+ME_WAITTANG), filename, my_errno); + } + my_close(fd, MYF(MY_WME)); + } + return(fd2); } /************************************************************************* From b81af1c7504e5a8084d232131817abc20401adda Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 19 Aug 2004 23:10:33 +0200 Subject: [PATCH 10/13] less strict assert to take into account weird cases --- mysql-test/r/type_float.result | 3 +++ mysql-test/t/type_float.test | 7 +++++++ sql/field.cc | 6 ++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 61b90c8cf2e..f4c5df353a3 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -114,6 +114,9 @@ select min(a) from t1; min(a) -0.010 drop table t1; +create table t1 (c20 char); +insert into t1 (c20) values (5000.0); +drop table t1; create table t1 (f float(54)); Incorrect column specifier for column 'f' drop table if exists t1; diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index bd6448616dc..084d4b815e5 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -54,6 +54,13 @@ select a from t1 order by a; select min(a) from t1; drop table t1; +# +# float in a char(1) field +# +create table t1 (c20 char); +insert into t1 (c20) values (5000.0); +drop table t1; + # Errors --error 1063 diff --git a/sql/field.cc b/sql/field.cc index 1b5c688fe7a..71ec7545efc 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3733,15 +3733,17 @@ static void store_double_in_string_field(Field_str *field, uint32 field_length, use_scientific_notation= (field->ceiling < nr); } length= (uint)sprintf(buff, "%-.*g", - use_scientific_notation ? max(0,field_length-5) : field_length, + use_scientific_notation ? max(0,(int)field_length-5) : field_length, nr); /* +1 below is because "precision" in %g above means the max. number of significant digits, not the output width. Thus the width can be larger than number of significant digits by 1 (for decimal point) + the test for field_length < 5 is for extreme cases, + like inserting 500.0 in char(1) */ - DBUG_ASSERT(length <= field_length+1); + DBUG_ASSERT(field_length < 5 || length <= field_length+1); field->store(buff, min(length, field_length)); } From 0db5b4d2029ccb1581c24cd22ad8305b9506719c Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Thu, 19 Aug 2004 23:24:35 +0200 Subject: [PATCH 11/13] (manual port from 4.0 - was needed) Fix for BUG#4971 "CREATE TABLE ... TYPE=HEAP SELECT ... stops slave (wrong DELETE in binlog)": replacing the no_log argument of mysql_create_table() by some safer method (temporarily setting OPTION_BIN_LOG to 0) which guarantees that even the automatic DELETE FROM heap_table does not get into the binlog when a not-yet-existing HEAP table is opened by mysql_create_table(). --- mysql-test/r/rpl_heap.result | 12 ++++++------ mysql-test/t/rpl_heap.test | 6 ++++-- sql/log.cc | 14 ++++++++++++++ sql/mysql_priv.h | 2 +- sql/sql_class.h | 21 +++++++++++++++++++++ sql/sql_parse.cc | 2 +- sql/sql_table.cc | 31 +++++++++++++++++++++---------- 7 files changed, 68 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/rpl_heap.result b/mysql-test/r/rpl_heap.result index 1556bcd5f25..1facbcb7676 100644 --- a/mysql-test/r/rpl_heap.result +++ b/mysql-test/r/rpl_heap.result @@ -1,22 +1,22 @@ reset master; drop table if exists t1; -create table t1 (a int) type=HEAP; -insert into t1 values(10); +create table t1 type=HEAP select 10 as a; +insert into t1 values(11); show binlog events from 79; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.001 79 Query 1 79 use `test`; create table t1 (a int) type=HEAP -master-bin.001 147 Query 1 147 use `test`; DELETE FROM `test`.`t1` -master-bin.001 205 Query 1 205 use `test`; insert into t1 values(10) +master-bin.001 79 Query 1 79 use `test`; create table t1 type=HEAP select 10 as a +master-bin.001 154 Query 1 154 use `test`; insert into t1 values(11) reset slave; start slave; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` int(11) default NULL + `a` bigint(2) NOT NULL default '0' ) TYPE=HEAP select * from t1; a 10 +11 select * from t1; a select * from t1 limit 10; diff --git a/mysql-test/t/rpl_heap.test b/mysql-test/t/rpl_heap.test index 15f61918034..0bc71eaf30c 100644 --- a/mysql-test/t/rpl_heap.test +++ b/mysql-test/t/rpl_heap.test @@ -13,8 +13,10 @@ connect (slave,localhost,root,,test,0,slave.sock); connection master; reset master; drop table if exists t1; -create table t1 (a int) type=HEAP; -insert into t1 values(10); +# we use CREATE SELECT to verify that DELETE does not get into binlog +# before CREATE SELECT +create table t1 type=HEAP select 10 as a; +insert into t1 values(11); save_master_pos; show binlog events from 79; connection slave; diff --git a/sql/log.cc b/sql/log.cc index ac412f2de9a..bcac7267f8b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1877,6 +1877,20 @@ void MYSQL_LOG::set_max_size(ulong max_size_arg) } +Disable_binlog::Disable_binlog(THD *thd_arg) : + thd(thd_arg), + save_options(thd_arg->options) +{ + thd_arg->options&= ~OPTION_BIN_LOG; +}; + + +Disable_binlog::~Disable_binlog() +{ + thd->options= save_options; +} + + /* Check if a string is a valid number diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9ada2fba164..4b8a14474fa 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -518,7 +518,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, int mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List &fields, List &keys, - bool tmp_table, bool no_log, uint select_field_count); + bool tmp_table, uint select_field_count); TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, const char *db, const char *name, List *extra_fields, diff --git a/sql/sql_class.h b/sql/sql_class.h index 59ac8ff0483..1fb2d5071f6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1017,6 +1017,27 @@ public: #define SYSTEM_THREAD_SLAVE_IO 2 #define SYSTEM_THREAD_SLAVE_SQL 4 +/* + Disables binary logging for one thread, and resets it back to what it was + before being disabled. + Some functions (like the internal mysql_create_table() when it's called by + mysql_alter_table()) must NOT write to the binlog (binlogging is done at the + at a later stage of the command already, and must be, for locking reasons); + so we internally disable it temporarily by creating the Disable_binlog + object and reset the state by destroying the object (don't forget that! or + write code so that the object gets automatically destroyed when leaving a + function...). +*/ +class Disable_binlog { +private: + THD *thd; + ulong save_options; + ulong save_master_access; +public: + Disable_binlog(THD *thd_arg); + ~Disable_binlog(); +}; + /* Used to hold information about file and file structure in exchainge via non-DB file (...INTO OUTFILE..., ...LOAD DATA...) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5aa4a8de156..41d7c471fe5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2379,7 +2379,7 @@ mysql_execute_command(THD *thd) res= mysql_create_table(thd,create_table->db, create_table->real_name, &lex->create_info, lex->create_list, - lex->key_list,0,0,0); // do logging + lex->key_list,0,0); } if (!res) send_ok(thd); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c82bff05412..9ff46f219b1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1090,7 +1090,6 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, keys List of keys to create tmp_table Set to 1 if this is an internal temporary table (From ALTER TABLE) - no_log Don't log the query to binary log. DESCRIPTION If one creates a temporary table, this is automaticly opened @@ -1108,7 +1107,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, int mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List &fields, - List &keys,bool tmp_table,bool no_log, + List &keys,bool tmp_table, uint select_field_count) { char path[FN_REFLEN]; @@ -1277,7 +1276,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } thd->tmp_table_used= 1; } - if (!tmp_table && !no_log) + if (!tmp_table) { // Must be written before unlock mysql_update_log.write(thd,thd->query, thd->query_length); @@ -1352,6 +1351,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, TABLE *table; tmp_table.table_name=0; uint select_field_count= items->elements; + Disable_binlog disable_binlog(thd); DBUG_ENTER("create_table_from_items"); /* Add selected items to field list */ @@ -1382,9 +1382,17 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } /* create and lock table */ /* QQ: This should be done atomic ! */ + /* We don't log the statement, it will be logged later */ if (mysql_create_table(thd,db,name,create_info,*extra_fields, - *keys,0,1,select_field_count)) // no logging + *keys,0,select_field_count)) DBUG_RETURN(0); + /* + If this is a HEAP table, the automatic DELETE FROM which is written to the + binlog when a HEAP table is opened for the first time since startup, must + not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we + don't want to delete from it) 2) it would be written before the CREATE + TABLE, which is a wrong order. So we keep binary logging disabled. + */ if (!(table=open_table(thd,db,name,name,(bool*) 0))) { quick_rm_table(create_info->db_type,db,table_case_name(create_info,name)); @@ -1401,6 +1409,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } table->file->extra(HA_EXTRA_WRITE_CACHE); DBUG_RETURN(table); + /* Note that leaving the function resets binlogging properties */ } @@ -3008,12 +3017,14 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } else create_info->data_file_name=create_info->index_file_name=0; - - if ((error=mysql_create_table(thd, new_db, tmp_name, - create_info, - create_list,key_list,1,1,0))) // no logging - DBUG_RETURN(error); - + { + /* We don't log the statement, it will be logged later */ + Disable_binlog disable_binlog(thd); + if ((error=mysql_create_table(thd, new_db, tmp_name, + create_info, + create_list,key_list,1,0))) + DBUG_RETURN(error); + } if (table->tmp_table) new_table=open_table(thd,new_db,tmp_name,tmp_name,0); else From 54d43b7b193d23d8f5524375b2d456d395a84694 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 20 Aug 2004 00:01:00 +0200 Subject: [PATCH 12/13] sql_class.h: removing unneeded var left from 4.0 --- sql/sql_class.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 1fb2d5071f6..32adc462743 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1032,7 +1032,6 @@ class Disable_binlog { private: THD *thd; ulong save_options; - ulong save_master_access; public: Disable_binlog(THD *thd_arg); ~Disable_binlog(); From 4f57cee99fec7d8d86b417067032579ff4379254 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 20 Aug 2004 01:34:34 +0200 Subject: [PATCH 13/13] typo in libedit fixed - possible buffer overflow - bug#4696 --- cmd-line-utils/libedit/history.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c index 90d94e7fc18..457c8f4a768 100644 --- a/cmd-line-utils/libedit/history.c +++ b/cmd-line-utils/libedit/history.c @@ -649,7 +649,7 @@ history_save(History *h, const char *fname) retval = HPREV(h, &ev), i++) { len = strlen(ev.str) * 4; if (len >= max_size) { - max_size = (len + 1023) & 1023; + max_size = (len + 1023) & ~1023; ptr = h_realloc(ptr, max_size); } (void) strvis(ptr, ev.str, VIS_WHITE);