diff options
author | unknown <monty@narttu.mysql.fi> | 2003-08-29 13:44:35 +0300 |
---|---|---|
committer | unknown <monty@narttu.mysql.fi> | 2003-08-29 13:44:35 +0300 |
commit | 0fa5279543d20c0d0c9ef6a1835c7f5056f0a997 (patch) | |
tree | aeb2314adbd714c7e2b032209bfd7914e3cfda3d /sql | |
parent | fb3ab3c855fa8f154d1f018bb6eea155614289c9 (diff) | |
parent | f2adc9f3dd62a9f1f7493d8401542bc8a007fe47 (diff) | |
download | mariadb-git-0fa5279543d20c0d0c9ef6a1835c7f5056f0a997.tar.gz |
merge with 4.0.15
BitKeeper/etc/ignore:
auto-union
BitKeeper/etc/logging_ok:
auto-union
BitKeeper/deleted/.del-database.c~af098622e818ce0d:
Auto merged
BitKeeper/deleted/.del-have_openssl_2.inc~8c9f1a45676b698f:
Auto merged
BitKeeper/deleted/.del-have_openssl_2.require~53bbdfc136fb514:
Auto merged
BitKeeper/deleted/.del-mini_client.cc~8677895ec8169183:
Auto merged
BitKeeper/deleted/.del-openssl_2.test~f2dfa927f19d14f8:
Auto merged
Build-tools/Bootstrap:
Auto merged
Build-tools/Do-compile:
Auto merged
SSL/cacert.pem:
Auto merged
acconfig.h:
Auto merged
acinclude.m4:
Auto merged
configure.in:
Auto merged
SSL/client-cert.pem:
Auto merged
SSL/client-key.pem:
Auto merged
SSL/server-cert.pem:
Auto merged
SSL/server-key.pem:
Auto merged
VC++Files/client/mysql.dsp:
Auto merged
VC++Files/client/mysqladmin.dsp:
Auto merged
VC++Files/client/mysqlclient.dsp:
Auto merged
VC++Files/client/mysqldump.dsp:
Auto merged
VC++Files/client/mysqlimport.dsp:
Auto merged
VC++Files/client/mysqlshow.dsp:
Auto merged
VC++Files/comp_err/comp_err.dsp:
Auto merged
VC++Files/innobase/innobase.dsp:
Auto merged
VC++Files/isamchk/isamchk.dsp:
Auto merged
VC++Files/libmysql/libmysql.dsp:
Auto merged
VC++Files/libmysqltest/myTest.dsp:
Auto merged
VC++Files/my_print_defaults/my_print_defaults.dsp:
Auto merged
VC++Files/myisamlog/myisamlog.dsp:
Auto merged
VC++Files/mysql.dsw:
Auto merged
VC++Files/mysqlbinlog/mysqlbinlog.dsp:
Auto merged
VC++Files/mysqlcheck/mysqlcheck.dsp:
Auto merged
VC++Files/mysqlmanager/MySqlManager.dsp:
Auto merged
VC++Files/mysqlserver/mysqlserver.dsp:
Auto merged
VC++Files/mysqlshutdown/mysqlshutdown.dsp:
Auto merged
VC++Files/mysys/mysys.dsp:
Auto merged
VC++Files/pack_isam/pack_isam.dsp:
Auto merged
VC++Files/perror/perror.dsp:
Auto merged
VC++Files/replace/replace.dsp:
Auto merged
VC++Files/test1/test1.dsp:
Auto merged
VC++Files/thr_test/thr_test.dsp:
Auto merged
VC++Files/vio/vio.dsp:
Auto merged
VC++Files/zlib/zlib.dsp:
Auto merged
client/mysqlbinlog.cc:
Auto merged
client/mysqldump.c:
Auto merged
client/mysqlimport.c:
Auto merged
extra/my_print_defaults.c:
Auto merged
extra/resolveip.c:
Auto merged
include/m_string.h:
Auto merged
include/my_sys.h:
Auto merged
include/mysql_com.h:
Auto merged
innobase/dict/dict0dict.c:
Auto merged
innobase/os/os0file.c:
Auto merged
isam/_search.c:
Auto merged
libmysql/Makefile.am:
Auto merged
libmysql/errmsg.c:
Auto merged
libmysql/libmysql.c:
Auto merged
myisam/mi_check.c:
Auto merged
myisam/mi_create.c:
Auto merged
myisam/mi_open.c:
Auto merged
myisam/mi_search.c:
Auto merged
myisam/mi_write.c:
Auto merged
myisam/myisamchk.c:
Auto merged
myisam/myisamlog.c:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
mysql-test/r/group_by.result:
Auto merged
mysql-test/r/isam.result:
Auto merged
mysql-test/r/loaddata.result:
Auto merged
mysql-test/r/lowercase_table.result:
Auto merged
mysql-test/r/multi_update.result:
Auto merged
mysql-test/r/openssl_1.result:
Auto merged
mysql-test/r/packet.result:
Auto merged
mysql-test/r/query_cache.result:
Auto merged
mysql-test/r/range.result:
Auto merged
mysql-test/r/select_safe.result:
Auto merged
mysql-test/r/show_check.result:
Auto merged
mysql-test/t/grant.test:
Auto merged
mysql-test/t/group_by.test:
Auto merged
mysql-test/t/lock_tables_lost_commit-master.opt:
Auto merged
mysql-test/t/lowercase_table.test:
Auto merged
mysql-test/t/multi_update.test:
Auto merged
mysql-test/t/openssl_1.test:
Auto merged
mysql-test/t/range.test:
Auto merged
mysql-test/t/rpl_loaddata.test:
Auto merged
mysql-test/t/rpl_log.test:
Auto merged
mysql-test/t/select_safe.test:
Auto merged
mysql-test/t/show_check.test:
Auto merged
mysql-test/t/symlink.test:
Auto merged
mysys/default.c:
Auto merged
mysys/my_getopt.c:
Auto merged
mysys/my_pthread.c:
Auto merged
scripts/make_binary_distribution.sh:
Auto merged
scripts/make_win_src_distribution.sh:
Auto merged
scripts/mysql_install_db.sh:
Auto merged
scripts/mysqld_safe.sh:
Auto merged
sql/ha_innodb.cc:
Auto merged
sql/ha_myisam.cc:
Auto merged
sql/handler.cc:
Auto merged
sql/item_uniq.h:
Auto merged
sql/log_event.h:
Auto merged
sql/net_serv.cc:
Auto merged
sql/repl_failsafe.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_load.cc:
Auto merged
sql/sql_repl.cc:
Auto merged
sql/sql_update.cc:
Auto merged
vio/Makefile.am:
Auto merged
vio/vio.c:
Auto merged
mysql-test/t/myisam.test:
merge with 4.0.15
Extra tests
mysys/mf_keycache.c:
Keep local file
Diffstat (limited to 'sql')
37 files changed, 869 insertions, 472 deletions
diff --git a/sql/field.cc b/sql/field.cc index 051a4fa8057..efdf1762c0b 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -771,7 +771,7 @@ int Field_decimal::store(double nr) char buff[320]; fyllchar = zerofill ? (char) '0' : (char) ' '; -#ifdef HAVE_SNPRINTF_ +#ifdef HAVE_SNPRINTF buff[sizeof(buff)-1]=0; // Safety snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr); length=(uint) strlen(buff); @@ -2016,9 +2016,16 @@ double Field_longlong::val_real(void) else #endif longlongget(j,ptr); - return unsigned_flag ? ulonglong2double((ulonglong) j) : (double) j; + /* The following is open coded to avoid a bug in gcc 3.3 */ + if (unsigned_flag) + { + ulonglong tmp= (ulonglong) j; + return ulonglong2double(tmp); + } + return (double) j; } + longlong Field_longlong::val_int(void) { longlong j; @@ -4413,8 +4420,11 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) Field_blob::store_length(length); if (table->copy_blobs || length <= MAX_FIELD_WIDTH) { // Must make a copy - value.copy(from,length,charset()); - from=value.ptr(); + if (from != value.ptr()) // For valgrind + { + value.copy(from,length,charset()); + from=value.ptr(); + } } bmove(ptr+packlength,(char*) &from,sizeof(char*)); } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index d870d0debfd..bcdb01da9ca 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -28,7 +28,6 @@ InnoDB */ #include "mysql_priv.h" #include "slave.h" -#include "sql_cache.h" #ifdef HAVE_INNOBASE_DB #include <m_ctype.h> diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index e8e4798c2b2..043cdafa275 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1109,7 +1109,7 @@ THR_LOCK_DATA **ha_myisam::store_lock(THD *thd, void ha_myisam::update_create_info(HA_CREATE_INFO *create_info) { - table->file->info(HA_STATUS_AUTO | HA_STATUS_CONST); + ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST); if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) { create_info->auto_increment_value=auto_increment_value; diff --git a/sql/handler.cc b/sql/handler.cc index b4d370491bb..a8e9f9cf50a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -359,7 +359,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) if (trans == &thd->transaction.all && mysql_bin_log.is_open() && my_b_tell(&thd->transaction.trans_log)) { - mysql_bin_log.write(thd, &thd->transaction.trans_log); + mysql_bin_log.write(thd, &thd->transaction.trans_log, 1); reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); thd->transaction.trans_log.end_of_file= max_binlog_cache_size; @@ -442,9 +442,21 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) } #endif if (trans == &thd->transaction.all) + { + /* + Update the binary log with a BEGIN/ROLLBACK block if we have cached some + queries and we updated some non-transactional table. Such cases should + be rare (updating a non-transactional table inside a transaction...). + */ + if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && + mysql_bin_log.is_open() && + my_b_tell(&thd->transaction.trans_log))) + mysql_bin_log.write(thd, &thd->transaction.trans_log, 0); + /* Flushed or not, empty the binlog cache */ reinit_io_cache(&thd->transaction.trans_log, - WRITE_CACHE, (my_off_t) 0, 0, 1); - thd->transaction.trans_log.end_of_file= max_binlog_cache_size; + WRITE_CACHE, (my_off_t) 0, 0, 1); + thd->transaction.trans_log.end_of_file= max_binlog_cache_size; + } thd->variables.tx_isolation=thd->session_tx_isolation; if (operation_done) { @@ -458,9 +470,27 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) /* -Rolls the current transaction back to a savepoint. -Return value: 0 if success, 1 if there was not a savepoint of the given -name. + Rolls the current transaction back to a savepoint. + Return value: 0 if success, 1 if there was not a savepoint of the given + name. + NOTE: how do we handle this (unlikely but legal) case: + [transaction] + [update to non-trans table] + [rollback to savepoint] ? + The problem occurs when a savepoint is before the update to the + non-transactional table. Then when there's a rollback to the savepoint, if we + simply truncate the binlog cache, we lose the part of the binlog cache where + the update is. If we want to not lose it, we need to write the SAVEPOINT + command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter + is easy: it's just write at the end of the binlog cache, but the former should + be *inserted* to the place where the user called SAVEPOINT. The solution is + that when the user calls SAVEPOINT, we write it to the binlog cache (so no + need to later insert it). As transactions are never intermixed in the binary log + (i.e. they are serialized), we won't have conflicts with savepoint names when + using mysqlbinlog or in the slave SQL thread. + Then when ROLLBACK TO SAVEPOINT is called, if we updated some + non-transactional table, we don't truncate the binlog cache but instead write + ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which + will chop the SAVEPOINT command from the binlog cache, which is good as in + that case there is no need to have it in the binlog). */ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name) @@ -485,8 +515,24 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name) error=1; } else - reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, - binlog_cache_pos, 0, 0); + { + /* + Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some + non-transactional table. Otherwise, truncate the binlog cache starting + from the SAVEPOINT command. + */ + if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && + mysql_bin_log.is_open() && + my_b_tell(&thd->transaction.trans_log))) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE); + if (mysql_bin_log.write(&qinfo)) + error= 1; + } + else + reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, + binlog_cache_pos, 0, 0); + } operation_done=1; #endif if (operation_done) @@ -515,6 +561,13 @@ int ha_savepoint(THD *thd, char *savepoint_name) #ifdef HAVE_INNOBASE_DB innobase_savepoint(thd,savepoint_name, binlog_cache_pos); #endif + /* Write it to the binary log (see comments of ha_rollback_to_savepoint). */ + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE); + if (mysql_bin_log.write(&qinfo)) + error= 1; + } } #endif /* USING_TRANSACTIONS */ DBUG_RETURN(error); @@ -1051,14 +1104,25 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, void ha_key_cache(void) { - if (keybuff_size) - (void) init_key_cache((ulong) keybuff_size); + /* + The following mutex is not really needed as long as keybuff_size is + treated as a long value, but we use the mutex here to guard for future + changes. + */ + pthread_mutex_lock(&LOCK_global_system_variables); + long tmp= (long) keybuff_size; + pthread_mutex_unlock(&LOCK_global_system_variables); + if (tmp) + (void) init_key_cache(tmp); } void ha_resize_key_cache(void) { - (void) resize_key_cache((ulong) keybuff_size); + pthread_mutex_lock(&LOCK_global_system_variables); + long tmp= (long) keybuff_size; + pthread_mutex_unlock(&LOCK_global_system_variables); + (void) resize_key_cache(tmp); } diff --git a/sql/item.cc b/sql/item.cc index 0ea2231ca4b..371ce0a947d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -903,6 +903,13 @@ void Item::make_field(Send_field *tmp_field) init_make_field(tmp_field, field_type()); } + +void Item_empty_string::make_field(Send_field *tmp_field) +{ + init_make_field(tmp_field,FIELD_TYPE_VAR_STRING); +} + + enum_field_types Item::field_type() const { return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING : diff --git a/sql/item.h b/sql/item.h index 07be964092a..12f047bbebc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -505,6 +505,7 @@ public: Item_empty_string(const char *header,uint length) :Item_string("",0, &my_charset_bin) { name=(char*) header; max_length=length;} + void make_field(Send_field *field); }; class Item_return_int :public Item_int diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3471ddd30e9..09b92d7df40 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -545,6 +545,7 @@ void Item_func_interval::fix_length_and_dec() used_tables_cache|= row->used_tables(); not_null_tables_cache&= row->not_null_tables(); with_sum_func= with_sum_func || row->with_sum_func; + const_item_cache&= row->const_item(); } @@ -1458,17 +1459,20 @@ void Item_func_in::fix_length_and_dec() DBUG_ASSERT(0); return; } - uint j=0; - for (uint i=1 ; i < arg_count ; i++) + if (array && !(current_thd->fatal_error)) // If not EOM { - array->set(j,args[i]); - if (!args[i]->null_value) // Skip NULL values - j++; - else - have_null= 1; + uint j=0; + for (uint i=1 ; i < arg_count ; i++) + { + array->set(j,args[i]); + if (!args[i]->null_value) // Skip NULL values + j++; + else + have_null= 1; + } + if ((array->used_count=j)) + array->sort(); } - if ((array->used_count=j)) - array->sort(); } else { @@ -1567,7 +1571,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) and_tables_cache= ~(table_map) 0; if (thd && check_stack_overrun(thd,buff)) - return 0; // Fatal error flag is set! + return 1; // Fatal error flag is set! while ((item=li++)) { table_map tmp_table_map; diff --git a/sql/item_func.cc b/sql/item_func.cc index 4bda8ae78cd..bfb62febce4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -173,13 +173,15 @@ bool Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { Item **arg,**arg_end; +#ifndef EMBEDDED_LIBRARY // Avoid compiler warning char buff[STACK_BUFF_ALLOC]; // Max argument in function +#endif used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; if (thd && check_stack_overrun(thd,buff)) - return 0; // Fatal error if flag is set! + return 1; // Fatal error if flag is set! if (arg_count) { // Print purify happy for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) @@ -1431,13 +1433,15 @@ bool udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, uint arg_count, Item **arguments) { +#ifndef EMBEDDED_LIBRARY // Avoid compiler warning char buff[STACK_BUFF_ALLOC]; // Max argument in function +#endif DBUG_ENTER("Item_udf_func::fix_fields"); if (thd) { if (check_stack_overrun(thd,buff)) - return 0; // Fatal error flag is set! + DBUG_RETURN(1); // Fatal error flag is set! } else thd=current_thd; // In WHERE / const clause diff --git a/sql/item_func.h b/sql/item_func.h index 7fedbcf48ee..2b114f5c87d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -538,6 +538,7 @@ public: String *val_str(String *); void fix_length_and_dec(); enum Item_result result_type () const { return cmp_type; } + table_map not_null_tables() const { return 0; } }; class Item_func_min :public Item_func_min_max diff --git a/sql/item_sum.cc b/sql/item_sum.cc index c429346a2e6..de6282b1324 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -70,6 +70,8 @@ void Item_sum::make_field(Send_field *tmp_field) tmp_field->db_name=(char*)""; tmp_field->org_table_name=tmp_field->table_name=(char*)""; tmp_field->org_col_name=tmp_field->col_name=name; + if (maybe_null) + tmp_field->flags&= ~NOT_NULL_FLAG; } else init_make_field(tmp_field, field_type()); @@ -197,7 +199,8 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) max_length=item->max_length; } decimals=item->decimals; - maybe_null=item->maybe_null; + /* MIN/MAX can return NULL for empty set indepedent of the used column */ + maybe_null= 1; unsigned_flag=item->unsigned_flag; collation.set(item->collation); result_field=0; @@ -388,15 +391,15 @@ void Item_sum_variance::reset_field() } } -void Item_sum_variance::update_field(int offset) +void Item_sum_variance::update_field() { double nr,old_nr,old_sqr; longlong field_count; char *res=result_field->ptr; - float8get(old_nr,res+offset); - float8get(old_sqr,res+offset+sizeof(double)); - field_count=sint8korr(res+offset+sizeof(double)*2); + float8get(old_nr, res); + float8get(old_sqr, res+sizeof(double)); + field_count=sint8korr(res+sizeof(double)*2); nr=args[0]->val(); if (!args[0]->null_value) @@ -753,12 +756,12 @@ void Item_sum_bit::reset_field() ** calc next value and merge it with field_value */ -void Item_sum_sum::update_field(int offset) +void Item_sum_sum::update_field() { double old_nr,nr; char *res=result_field->ptr; - float8get(old_nr,res+offset); + float8get(old_nr,res); nr=args[0]->val(); if (!args[0]->null_value) { @@ -769,12 +772,12 @@ void Item_sum_sum::update_field(int offset) } -void Item_sum_count::update_field(int offset) +void Item_sum_count::update_field() { longlong nr; char *res=result_field->ptr; - nr=sint8korr(res+offset); + nr=sint8korr(res); if (!args[0]->maybe_null) nr++; else @@ -787,14 +790,14 @@ void Item_sum_count::update_field(int offset) } -void Item_sum_avg::update_field(int offset) +void Item_sum_avg::update_field() { double nr,old_nr; longlong field_count; char *res=result_field->ptr; - float8get(old_nr,res+offset); - field_count=sint8korr(res+offset+sizeof(double)); + float8get(old_nr,res); + field_count=sint8korr(res+sizeof(double)); nr=args[0]->val(); if (!args[0]->null_value) @@ -807,77 +810,65 @@ void Item_sum_avg::update_field(int offset) int8store(res,field_count); } -void Item_sum_hybrid::update_field(int offset) +void Item_sum_hybrid::update_field() { if (hybrid_type == STRING_RESULT) - min_max_update_str_field(offset); + min_max_update_str_field(); else if (hybrid_type == INT_RESULT) - min_max_update_int_field(offset); + min_max_update_int_field(); else - min_max_update_real_field(offset); + min_max_update_real_field(); } void -Item_sum_hybrid::min_max_update_str_field(int offset) +Item_sum_hybrid::min_max_update_str_field() { String *res_str=args[0]->val_str(&value); - if (args[0]->null_value) - result_field->copy_from_tmp(offset); // Use old value - else + if (!args[0]->null_value) { res_str->strip_sp(); - result_field->ptr+=offset; // Get old max/min result_field->val_str(&tmp_value,&tmp_value); - result_field->ptr-=offset; if (result_field->is_null() || (cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0) result_field->store(res_str->ptr(),res_str->length(),res_str->charset()); - else - { // Use old value - char *res=result_field->ptr; - memcpy(res,res+offset,result_field->pack_length()); - } result_field->set_notnull(); } } void -Item_sum_hybrid::min_max_update_real_field(int offset) +Item_sum_hybrid::min_max_update_real_field() { double nr,old_nr; - result_field->ptr+=offset; old_nr=result_field->val_real(); nr=args[0]->val(); if (!args[0]->null_value) { - if (result_field->is_null(offset) || + if (result_field->is_null(0) || (cmp_sign > 0 ? old_nr > nr : old_nr < nr)) old_nr=nr; result_field->set_notnull(); } - else if (result_field->is_null(offset)) + else if (result_field->is_null(0)) result_field->set_null(); - result_field->ptr-=offset; result_field->store(old_nr); } void -Item_sum_hybrid::min_max_update_int_field(int offset) +Item_sum_hybrid::min_max_update_int_field() { longlong nr,old_nr; - result_field->ptr+=offset; old_nr=result_field->val_int(); nr=args[0]->val_int(); if (!args[0]->null_value) { - if (result_field->is_null(offset)) + if (result_field->is_null(0)) old_nr=nr; else { @@ -890,30 +881,29 @@ Item_sum_hybrid::min_max_update_int_field(int offset) } result_field->set_notnull(); } - else if (result_field->is_null(offset)) + else if (result_field->is_null(0)) result_field->set_null(); - result_field->ptr-=offset; result_field->store(old_nr); } -void Item_sum_or::update_field(int offset) +void Item_sum_or::update_field() { ulonglong nr; char *res=result_field->ptr; - nr=uint8korr(res+offset); + nr=uint8korr(res); nr|= (ulonglong) args[0]->val_int(); int8store(res,nr); } -void Item_sum_and::update_field(int offset) +void Item_sum_and::update_field() { ulonglong nr; char *res=result_field->ptr; - nr=uint8korr(res+offset); + nr=uint8korr(res); nr&= (ulonglong) args[0]->val_int(); int8store(res,nr); } @@ -1931,6 +1921,3 @@ String* Item_func_group_concat::val_str(String* str) } return &result; } - - - diff --git a/sql/item_sum.h b/sql/item_sum.h index e9f9890f41d..6cc8d768be5 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -66,7 +66,7 @@ public: virtual void clear()= 0; virtual bool add()=0; virtual void reset_field()=0; - virtual void update_field(int offset)=0; + virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } virtual const char *func_name() const { return "?"; } @@ -129,7 +129,7 @@ class Item_sum_sum :public Item_sum_num bool add(); double val(); void reset_field(); - void update_field(int offset); + void update_field(); void no_rows_in_result() {} const char *func_name() const { return "sum"; } Item *copy_or_same(THD* thd); @@ -158,7 +158,7 @@ class Item_sum_count :public Item_sum_int void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; } longlong val_int(); void reset_field(); - void update_field(int offset); + void update_field(); const char *func_name() const { return "count"; } Item *copy_or_same(THD* thd); }; @@ -230,7 +230,7 @@ class Item_sum_count_distinct :public Item_sum_int bool add(); longlong val_int(); void reset_field() { return ;} // Never called - void update_field(int offset) { return ; } // Never called + void update_field() { return ; } // Never called const char *func_name() const { return "count_distinct"; } bool setup(THD *thd); void make_unique(); @@ -274,7 +274,7 @@ class Item_sum_avg :public Item_sum_num bool add(); double val(); void reset_field(); - void update_field(int offset); + void update_field(); Item *result_item(Field *field) { return new Item_avg_field(this); } const char *func_name() const { return "avg"; } @@ -327,7 +327,7 @@ class Item_sum_variance : public Item_sum_num bool add(); double val(); void reset_field(); - void update_field(int offset); + void update_field(); Item *result_item(Field *field) { return new Item_variance_field(this); } const char *func_name() const { return "variance"; } @@ -407,10 +407,10 @@ class Item_sum_hybrid :public Item_sum bool keep_field_type(void) const { return 1; } enum Item_result result_type () const { return hybrid_type; } enum enum_field_types field_type() const { return hybrid_field_type; } - void update_field(int offset); - void min_max_update_str_field(int offset); - void min_max_update_real_field(int offset); - void min_max_update_int_field(int offset); + void update_field(); + void min_max_update_str_field(); + void min_max_update_real_field(); + void min_max_update_int_field(); }; @@ -465,7 +465,7 @@ class Item_sum_or :public Item_sum_bit Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_or(THD *thd, Item_sum_or &item) :Item_sum_bit(thd, item) {} bool add(); - void update_field(int offset); + void update_field(); const char *func_name() const { return "bit_or"; } Item *copy_or_same(THD* thd); }; @@ -477,7 +477,7 @@ class Item_sum_and :public Item_sum_bit Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {} Item_sum_and(THD *thd, Item_sum_and &item) :Item_sum_bit(thd, item) {} bool add(); - void update_field(int offset); + void update_field(); const char *func_name() const { return "bit_and"; } Item *copy_or_same(THD* thd); }; @@ -512,7 +512,7 @@ public: void clear(); bool add(); void reset_field() {}; - void update_field(int offset_arg) {}; + void update_field() {}; }; @@ -593,7 +593,7 @@ class Item_sum_udf_float :public Item_sum_num double val() { return 0.0; } void clear() {} bool add() { return 0; } - void update_field(int offset) {} + void update_field() {} }; @@ -610,7 +610,7 @@ public: double val() { return 0; } void clear() {} bool add() { return 0; } - void update_field(int offset) {} + void update_field() {} }; @@ -630,7 +630,7 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } void clear() {} bool add() { return 0; } - void update_field(int offset) {} + void update_field() {} }; #endif /* HAVE_DLOPEN */ @@ -720,7 +720,7 @@ class Item_func_group_concat : public Item_sum bool fix_fields(THD *, TABLE_LIST *, Item **); bool setup(THD *thd); void make_unique(); - virtual void update_field(int offset) {}; + virtual void update_field() {} double val() { String *res; res=val_str(&str_value); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index e41397dac44..9b370b70181 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -44,7 +44,7 @@ public: void clear() {} bool add() { return 0; } void reset_field() {} - void update_field(int offset) {} + void update_field() {} bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { fixed= 1; diff --git a/sql/log.cc b/sql/log.cc index d3ba5b63e19..f279d6d679c 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -270,7 +270,8 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, an extension for the binary log files. In this case we write a standard header to it. */ - if (my_b_write(&log_file, (byte*) BINLOG_MAGIC, BIN_LOG_HEADER_SIZE)) + if (my_b_safe_write(&log_file, (byte*) BINLOG_MAGIC, + BIN_LOG_HEADER_SIZE)) goto err; bytes_written += BIN_LOG_HEADER_SIZE; write_file_name_to_index_file=1; @@ -1175,14 +1176,24 @@ bool MYSQL_LOG::write(Log_event* event_info) */ if (is_open()) { - const char *local_db = event_info->get_db(); + const char *local_db= event_info->get_db(); + IO_CACHE *file= &log_file; #ifdef USING_TRANSACTIONS - IO_CACHE *file = ((event_info->get_cache_stmt()) ? - &thd->transaction.trans_log : - &log_file); -#else - IO_CACHE *file = &log_file; -#endif + /* + Should we write to the binlog cache or to the binlog on disk? + Write to the binlog cache if: + - it is already not empty (meaning we're in a transaction; note that the + present event could be about a non-transactional table, but still we need + to write to the binlog cache in that case to handle updates to mixed + trans/non-trans table types the best possible in binlogging) + - or if the event asks for it (cache_stmt == true). + */ + if (opt_using_transactions && + (event_info->get_cache_stmt() || + (thd && my_b_tell(&thd->transaction.trans_log)))) + file= &thd->transaction.trans_log; +#endif + DBUG_PRINT("info",("event type=%d",event_info->get_type_code())); #ifdef HAVE_REPLICATION /* In the future we need to add to the following if tests like @@ -1401,6 +1412,13 @@ uint MYSQL_LOG::next_file_id() /* Write a cached log entry to the binary log + SYNOPSIS + write() + thd + cache The cache to copy to the binlog + commit_or_rollback If true, will write "COMMIT" in the end, if false will + write "ROLLBACK". + NOTE - We only come here if there is something in the cache. - The thing in the cache is always a complete transaction @@ -1408,10 +1426,13 @@ uint MYSQL_LOG::next_file_id() IMPLEMENTATION - To support transaction over replication, we wrap the transaction - with BEGIN/COMMIT in the binary log. + with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log. + We want to write a BEGIN/ROLLBACK block when a non-transactional table was + updated in a transaction which was rolled back. This is to ensure that the + same updates are run on the slave. */ -bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) +bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback) { VOID(pthread_mutex_lock(&LOCK_log)); DBUG_ENTER("MYSQL_LOG::write(cache"); @@ -1465,7 +1486,10 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) */ { - Query_log_event qinfo(thd, "COMMIT", 6, TRUE); + Query_log_event qinfo(thd, + commit_or_rollback ? "COMMIT" : "ROLLBACK", + commit_or_rollback ? 6 : 8, + TRUE); qinfo.set_log_pos(this); if (qinfo.write(&log_file) || flush_io_cache(&log_file)) goto err; @@ -1642,6 +1666,9 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, SYNOPSIS wait_for_update() thd Thread variable + master_or_slave If 0, the caller is the Binlog_dump thread from master; + if 1, the caller is the SQL thread from the slave. This + influences only thd->proc_info. NOTES One must have a lock on LOCK_log before calling this function. @@ -1653,11 +1680,15 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, If you don't do it this way, you will get a deadlock in THD::awake() */ -void MYSQL_LOG:: wait_for_update(THD* thd) +void MYSQL_LOG:: wait_for_update(THD* thd, bool master_or_slave) { safe_mutex_assert_owner(&LOCK_log); const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log, - "Slave: waiting for binlog update"); + master_or_slave ? + "Has read all relay log; waiting for \ +the I/O slave thread to update it" : + "Has sent all binlog to slave; \ +waiting for binlog to be updated"); pthread_cond_wait(&update_cond, &LOCK_log); pthread_mutex_unlock(&LOCK_log); // See NOTES thd->exit_cond(old_msg); diff --git a/sql/log_event.cc b/sql/log_event.cc index 8a52ad9ebca..48c2000d11b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -27,25 +27,6 @@ #define log_cs &my_charset_latin1 /* - my_b_safe_write() -*/ - -inline int my_b_safe_write(IO_CACHE* file, const byte *buf, - int len) -{ - /* - Sasha: We are not writing this with the ? operator to avoid hitting - a possible compiler bug. At least gcc 2.95 cannot deal with - several layers of ternary operators that evaluated comma(,) operator - expressions inside - I do have a test case if somebody wants it - */ - if (file->type == SEQ_READ_APPEND) - return my_b_append(file, buf,len); - return my_b_write(file, buf,len); -} - - -/* pretty_print_str() */ @@ -239,12 +220,11 @@ const char* Log_event::get_type_str() #ifndef MYSQL_CLIENT Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans) - :temp_buf(0), exec_time(0), cached_event_len(0), flags(flags_arg), - thd(thd_arg) + :log_pos(0), temp_buf(0), exec_time(0), cached_event_len(0), + flags(flags_arg), thd(thd_arg) { server_id= thd->server_id; when= thd->start_time; - log_pos= thd->log_pos; cache_stmt= (using_trans && (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))); } @@ -331,7 +311,6 @@ int Log_event::exec_event(struct st_relay_log_info* rli) handler and MyISAM and STOP SLAVE is issued in the middle of the "transaction". START SLAVE will resume at BEGIN while the MyISAM table has already been updated. - */ if ((thd->options & OPTION_BEGIN) && opt_using_transactions) rli->inc_event_relay_log_pos(get_event_len()); @@ -605,6 +584,8 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, ev = new Query_log_event(buf, event_len, old_format); break; case LOAD_EVENT: + ev = new Create_file_log_event(buf, event_len, old_format); + break; case NEW_LOAD_EVENT: ev = new Load_log_event(buf, event_len, old_format); break; @@ -932,6 +913,18 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) mysql_parse(thd, thd->query, q_len); /* + Set a flag if we are inside an transaction so that we can restart + the transaction from the start if we are killed + + This will only be done if we are supporting transactional tables + in the slave. + */ + if (!strcmp(thd->query,"BEGIN")) + rli->inside_transaction= opt_using_transactions; + else if (!(strcmp(thd->query,"COMMIT") && strcmp(thd->query,"ROLLBACK"))) + rli->inside_transaction=0; + + /* If we expected a non-zero error code, and we don't get the same error code, and none of them should be ignored. */ @@ -988,14 +981,14 @@ Default database: '%s'", */ } /* End of if (db_ok(... */ -end: - VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->db= 0; // prevent db from being freed thd->query= 0; // just to be sure VOID(pthread_mutex_unlock(&LOCK_thread_count)); // assume no convert for next query unless set explictly - //thd->variables.convert_set = 0; +#ifdef TO_BE_REMOVED + thd->variables.convert_set = 0; +#endif close_thread_tables(thd); free_root(&thd->mem_root,0); return (thd->query_error ? thd->query_error : Log_event::exec_event(rli)); @@ -1091,15 +1084,6 @@ int Start_log_event::write_data(IO_CACHE* file) the use of a bit of memory for a user lock which will not be used anymore. If the user lock is later used, the old one will be released. In other words, no deadlock problem. - - If we have an active transaction at this point, the master died - in the middle while writing the transaction to the binary log. - In this case we should stop the slave. - Guilhem 2003-06: I don't think we should. As the binlog is written before - the table changes are committed, rollback has occured on the master; we - should rather rollback on the slave and go on. If we don't rollback, and - the next query is not BEGIN, then it will be considered as part of the - unfinished transaction, and so will be rolled back at next BEGIN, which - is a bug. */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) @@ -1471,6 +1455,13 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, #ifdef MYSQL_CLIENT void Load_log_event::print(FILE* file, bool short_form, char* last_db) { + print(file, short_form, last_db, 0); +} + + +void Load_log_event::print(FILE* file, bool short_form, char* last_db, + bool commented) +{ if (!short_form) { print_header(file); @@ -1486,9 +1477,12 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) } if (db && db[0] && !same_db) - fprintf(file, "use %s;\n", db); + fprintf(file, "%suse %s;\n", + commented ? "# " : "", + db); - fprintf(file, "LOAD DATA "); + fprintf(file, "%sLOAD DATA ", + commented ? "# " : ""); if (check_fname_outside_temp_buf()) fprintf(file, "LOCAL "); fprintf(file, "INFILE '%-*s' ", fname_len, fname); @@ -1535,8 +1529,8 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len); } - if ((int)skip_lines > 0) - fprintf(file, " IGNORE %ld LINES ", (long) skip_lines); + if ((long) skip_lines > 0) + fprintf(file, " IGNORE %ld LINES", (long) skip_lines); if (num_fields) { @@ -1613,6 +1607,18 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, thd->query = 0; // Should not be needed thd->query_error = 0; + /* + We test replicate_*_db rules. Note that we have already prepared the file + to load, even if we are going to ignore and delete it now. So it is + possible that we did a lot of disk writes for nothing. In other words, a + big LOAD DATA INFILE on the master will still consume a lot of space on + the slave (space in the relay log + space of temp files: twice the space + of the file to load...) even if it will finally be ignored. + TODO: fix this; this can be done by testing rules in + Create_file_log_event::exec_event() and then discarding Append_block and + al. Another way is do the filtering in the I/O thread (more efficient: no + disk writes at all). + */ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { thd->set_time((time_t)when); @@ -1642,20 +1648,22 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, else if (sql_ex.opt_flags & IGNORE_FLAG) handle_dup= DUP_IGNORE; else + { /* - Note that when replication is running fine, if it was DUP_ERROR on the + When replication is running fine, if it was DUP_ERROR on the master then we could choose DUP_IGNORE here, because if DUP_ERROR suceeded on master, and data is identical on the master and slave, then there should be no uniqueness errors on slave, so DUP_IGNORE is the same as DUP_ERROR. But in the unlikely case of uniqueness errors - (because the data on the master and slave happen to be different (user - error or bug), we want LOAD DATA to print an error message on the - slave to discover the problem. + (because the data on the master and slave happen to be different + (user error or bug), we want LOAD DATA to print an error message on + the slave to discover the problem. If reading from net (a 3.23 master), mysql_load() will change this to DUP_IGNORE. */ handle_dup= DUP_ERROR; + } sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG); String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs); @@ -1731,7 +1739,7 @@ Slave: load data infile on table '%s' at log position %s in log \ err=ER(sql_errno); } slave_print_error(rli,sql_errno,"\ -Error '%s' running lOAD DATA INFILE on table '%s'. Default database: '%s'", +Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'", err, (char*)table_name, print_slave_db_safe(db)); free_root(&thd->mem_root,0); return 1; @@ -1762,14 +1770,13 @@ Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'", #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Rotate_log_event::pack_info(Protocol *protocol) { - char *buf, *b_pos; - if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME)))) - return; - memcpy(buf, new_log_ident, ident_len); - b_pos= strmov(buf + ident_len, ";pos="); - b_pos= longlong10_to_str(pos, b_pos, 10); - protocol->store(buf, (uint) (b_pos-buf), &my_charset_bin); - my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); + char buf1[256], buf[22]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + tmp.append(new_log_ident, ident_len); + tmp.append(";pos="); + tmp.append(llstr(pos,buf)); + protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin); } #endif @@ -1858,6 +1865,25 @@ int Rotate_log_event::write_data(IO_CACHE* file) We can't rotate the slave as this will cause infinitive rotations in a A -> B -> A setup. + NOTES + As a transaction NEVER spans on 2 or more binlogs: + if we have an active transaction at this point, the master died while + writing the transaction to the binary log, i.e. while flushing the binlog + cache to the binlog. As the write was started, the transaction had been + committed on the master, so we lack of information to replay this + transaction on the slave; all we can do is stop with error. + If we didn't detect it, then positions would start to become garbage (as we + are incrementing rli->relay_log_pos whereas we are in a transaction: the + new rli->relay_log_pos will be + relay_log_pos of the BEGIN + size of the Rotate event = garbage. + + Since MySQL 4.0.14, the master ALWAYS sends a Rotate event when it starts + sending the next binlog, so we are sure to receive a Rotate event just + after the end of the "dead master"'s binlog; so this exec_event() is the + right place to catch the problem. If we would wait until + Start_log_event::exec_event() it would be too late, rli->relay_log_pos + would already be garbage. + RETURN VALUES 0 ok */ @@ -1869,6 +1895,18 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) DBUG_ENTER("Rotate_log_event::exec_event"); pthread_mutex_lock(&rli->data_lock); + + if (rli->inside_transaction) + { + slave_print_error(rli, 0, + "there is an unfinished transaction in the relay log \ +(could find neither COMMIT nor ROLLBACK in the relay log); it could be that \ +the master died while writing the transaction to its binary log. Now the slave \ +is rolling back the transaction."); + pthread_mutex_unlock(&rli->data_lock); + DBUG_RETURN(1); + } + memcpy(log_name, new_log_ident, ident_len+1); rli->group_master_log_pos = pos; rli->event_relay_log_pos += get_event_len(); @@ -1894,8 +1932,8 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Intvar_log_event::pack_info(Protocol *protocol) { - char buf[64], *pos; - pos= strmov(buf, get_var_type_name()); + char buf[256], *pos; + pos= strmake(buf, get_var_type_name(), sizeof(buf)-23); *pos++= '='; pos= longlong10_to_str(val, pos, -10); protocol->store(buf, (uint) (pos-buf), &my_charset_bin); @@ -2462,8 +2500,8 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db) Stop_log_event::exec_event() The master stopped. - We used to clean up all temporary tables but this is useless as, as the master - has shut down properly, it has written all DROP TEMPORARY TABLE and DO + We used to clean up all temporary tables but this is useless as, as the + master has shut down properly, it has written all DROP TEMPORARY TABLE and DO RELEASE_LOCK (prepared statements' deletion is TODO). We used to clean up slave_load_tmpdir, but this is useless as it has been cleared at the end of LOAD DATA INFILE. @@ -2605,10 +2643,12 @@ void Create_file_log_event::print(FILE* file, bool short_form, if (enable_local) { - if (!check_fname_outside_temp_buf()) - fprintf(file, "#"); - Load_log_event::print(file, 1, last_db); - fprintf(file, "#"); + Load_log_event::print(file, 1, last_db, !check_fname_outside_temp_buf()); + /* + That one is for "file_id: etc" below: in mysqlbinlog we want the #, in + SHOW BINLOG EVENTS we don't. + */ + fprintf(file, "#"); } fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); @@ -2641,7 +2681,7 @@ void Create_file_log_event::pack_info(Protocol *protocol) pos= int10_to_str((long) block_len, pos, 10); protocol->store(buf, (uint) (pos-buf), &my_charset_bin); } -#endif +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ /* @@ -2665,7 +2705,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0, MYF(MY_WME|MY_NABP))) { - slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf); + slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf); goto err; } @@ -2676,7 +2716,9 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) if (write_base(&file)) { strmov(p, ".info"); // to have it right in the error message - slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf); + slave_print_error(rli,my_errno, + "Error in Create_file event: could not write to file '%s'", + fname_buf); goto err; } end_io_cache(&file); @@ -2686,16 +2728,14 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, MYF(MY_WME))) < 0) { - slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf); + slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf); goto err; } if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) { - slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf); + slave_print_error(rli,my_errno, "Error in Create_file event: write to '%s' failed", fname_buf); goto err; } - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); error=0; // Everything is ok err: @@ -2705,7 +2745,7 @@ err: my_close(fd, MYF(0)); return error ? 1 : Log_event::exec_event(rli); } -#endif +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ /************************************************************************** @@ -2717,11 +2757,12 @@ err: */ #ifndef MYSQL_CLIENT -Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, +Append_block_log_event::Append_block_log_event(THD* thd_arg, const char* db_arg, + char* block_arg, uint block_len_arg, bool using_trans) :Log_event(thd_arg,0, using_trans), block(block_arg), - block_len(block_len_arg), file_id(thd_arg->file_id) + block_len(block_len_arg), file_id(thd_arg->file_id), db(db_arg) { } #endif @@ -2787,7 +2828,7 @@ void Append_block_log_event::pack_info(Protocol *protocol) block_len)); protocol->store(buf, length, &my_charset_bin); } -#endif +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ /* @@ -2805,16 +2846,14 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) memcpy(p, ".data", 6); if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0) { - slave_print_error(rli,my_errno, "Could not open file '%s'", fname); + slave_print_error(rli,my_errno, "Error in Append_block event: could not open file '%s'", fname); goto err; } if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) { - slave_print_error(rli,my_errno, "Write to '%s' failed", fname); + slave_print_error(rli,my_errno, "Error in Append_block event: write to '%s' failed", fname); goto err; } - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); error=0; err: @@ -2834,8 +2873,9 @@ err: */ #ifndef MYSQL_CLIENT -Delete_file_log_event::Delete_file_log_event(THD *thd_arg, bool using_trans) - :Log_event(thd_arg, 0, using_trans),file_id(thd_arg->file_id) +Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg, + bool using_trans) + :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg) { } #endif @@ -2908,11 +2948,9 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) (void) my_delete(fname, MYF(MY_WME)); memcpy(p, ".info", 6); (void) my_delete(fname, MYF(MY_WME)); - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); return Log_event::exec_event(rli); } -#endif +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ /************************************************************************** @@ -2924,8 +2962,9 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) */ #ifndef MYSQL_CLIENT -Execute_load_log_event::Execute_load_log_event(THD *thd_arg, bool using_trans) - :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id) +Execute_load_log_event::Execute_load_log_event(THD *thd_arg, const char* db_arg, + bool using_trans) + :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg) { } #endif @@ -2997,7 +3036,6 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) char *p= slave_load_file_stem(fname, file_id, server_id); int fd; int error = 1; - ulong save_options; IO_CACHE file; Load_log_event* lev = 0; @@ -3006,7 +3044,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0, MYF(MY_WME|MY_NABP))) { - slave_print_error(rli,my_errno, "Could not open file '%s'", fname); + slave_print_error(rli,my_errno, "Error in Exec_load event: could not open file '%s'", fname); goto err; } if (!(lev = (Load_log_event*)Log_event::read_log_event(&file, @@ -3014,21 +3052,16 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) (bool)0)) || lev->get_type_code() != NEW_LOAD_EVENT) { - slave_print_error(rli,0, "File '%s' appears corrupted", fname); + slave_print_error(rli,0, "Error in Exec_load event: file '%s' appears corrupted", fname); goto err; } - /* - We are going to create a Load_log_event to finally load into the table. - This event should not go into the binlog: in the binlog we only want the - Create_file, Append_blocks and Execute_load. We disable binary logging and - restore the thread's options just after finishing the load. - */ - save_options = thd->options; - thd->options &= ~ (ulong) (OPTION_BIN_LOG); + lev->thd = thd; /* lev->exec_event should use rli only for errors - i.e. should not advance rli's position + i.e. should not advance rli's position. + lev->exec_event is the place where the table is loaded (it calls + mysql_load()). */ if (lev->exec_event(0,rli,1)) { @@ -3049,15 +3082,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) tmp, fname); my_free(tmp,MYF(0)); } - thd->options= save_options; goto err; } - thd->options = save_options; (void) my_delete(fname, MYF(MY_WME)); memcpy(p, ".data", 6); (void) my_delete(fname, MYF(MY_WME)); - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); error = 0; err: diff --git a/sql/log_event.h b/sql/log_event.h index a58479e2589..8ba5d0379a0 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -590,6 +590,7 @@ public: #endif /* HAVE_REPLICATION */ #else void print(FILE* file, bool short_form = 0, char* last_db = 0); + void print(FILE* file, bool short_form, char* last_db, bool commented); #endif Load_log_event(const char* buf, int event_len, bool old_format); @@ -934,9 +935,20 @@ public: char* block; uint block_len; uint file_id; - + /* + 'db' is filled when the event is created in mysql_load() (the event needs to + have a 'db' member to be well filtered by binlog-*-db rules). 'db' is not + written to the binlog (it's not used by Append_block_log_event::write()), so + it can't be read in the Append_block_log_event(const char* buf, int + event_len) constructor. + In other words, 'db' is used only for filtering by binlog-*-db rules. + Create_file_log_event is different: its 'db' (which is inherited from + Load_log_event) is written to the binlog and can be re-read. + */ + const char* db; + #ifndef MYSQL_CLIENT - Append_block_log_event(THD* thd, char* block_arg, + Append_block_log_event(THD* thd, const char* db_arg, char* block_arg, uint block_len_arg, bool using_trans); #ifdef HAVE_REPLICATION int exec_event(struct st_relay_log_info* rli); @@ -952,6 +964,7 @@ public: int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;} bool is_valid() { return block != 0; } int write_data(IO_CACHE* file); + const char* get_db() { return db; } }; /***************************************************************************** @@ -963,9 +976,10 @@ class Delete_file_log_event: public Log_event { public: uint file_id; + const char* db; /* see comment in Append_block_log_event */ #ifndef MYSQL_CLIENT - Delete_file_log_event(THD* thd, bool using_trans); + Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); @@ -981,6 +995,7 @@ public: int get_data_size() { return DELETE_FILE_HEADER_LEN ;} bool is_valid() { return file_id != 0; } int write_data(IO_CACHE* file); + const char* get_db() { return db; } }; /***************************************************************************** @@ -992,9 +1007,10 @@ class Execute_load_log_event: public Log_event { public: uint file_id; - + const char* db; /* see comment in Append_block_log_event */ + #ifndef MYSQL_CLIENT - Execute_load_log_event(THD* thd, bool using_trans); + Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); @@ -1009,6 +1025,7 @@ public: int get_data_size() { return EXEC_LOAD_HEADER_LEN ;} bool is_valid() { return file_id != 0; } int write_data(IO_CACHE* file); + const char* get_db() { return db; } }; #ifdef MYSQL_CLIENT diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a5d9ce5bce3..269846db446 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -212,16 +212,17 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MODE_NOT_USED 16 #define MODE_ONLY_FULL_GROUP_BY 32 #define MODE_NO_UNSIGNED_SUBTRACTION 64 -#define MODE_POSTGRESQL 128 -#define MODE_ORACLE 256 -#define MODE_MSSQL 512 -#define MODE_DB2 1024 -#define MODE_SAPDB 2048 -#define MODE_NO_KEY_OPTIONS 4096 -#define MODE_NO_TABLE_OPTIONS 8192 -#define MODE_NO_FIELD_OPTIONS 16384 -#define MODE_MYSQL323 32768 -#define MODE_MYSQL40 65536 +#define MODE_NO_DIR_IN_CREATE 128 +#define MODE_POSTGRESQL 256 +#define MODE_ORACLE 512 +#define MODE_MSSQL 1024 +#define MODE_DB2 2048 +#define MODE_SAPDB 4096 +#define MODE_NO_KEY_OPTIONS 8192 +#define MODE_NO_TABLE_OPTIONS 16384 +#define MODE_NO_FIELD_OPTIONS 32768 +#define MODE_MYSQL323 65536 +#define MODE_MYSQL40 (MODE_MYSQL323*2) #define MODE_ANSI (MODE_MYSQL40*2) #define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2) @@ -558,7 +559,8 @@ void mysqld_list_processes(THD *thd,const char *user,bool verbose); int mysqld_show_status(THD *thd); int mysqld_show_variables(THD *thd,const char *wild); int mysqld_show(THD *thd, const char *wild, show_var_st *variables, - enum enum_var_type value_type); + enum enum_var_type value_type, + pthread_mutex_t *mutex); int mysqld_show_charsets(THD *thd,const char *wild); int mysqld_show_collations(THD *thd,const char *wild); int mysqld_show_table_types(THD *thd); @@ -746,6 +748,7 @@ extern ulong ha_read_first_count, ha_read_last_count; extern ulong ha_read_rnd_count, ha_read_rnd_next_count; extern ulong ha_commit_count, ha_rollback_count,table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; +extern ulong slave_net_timeout; extern ulong max_insert_delayed_threads, max_user_connections; extern ulong long_query_count, what_to_log,flush_time; extern ulong query_buff_size, thread_stack,thread_stack_min; @@ -963,6 +966,12 @@ inline void mark_as_null_row(TABLE *table) bfill(table->null_flags,table->null_bytes,255); } +inline void table_case_convert(char * name, uint length) +{ + if (lower_case_table_names) + my_casedn(files_charset_info, name, length); +} + compare_func_creator comp_eq_creator(bool invert); compare_func_creator comp_ge_creator(bool invert); compare_func_creator comp_gt_creator(bool invert); @@ -979,6 +988,7 @@ compare_func_creator comp_ne_creator(bool invert); table_list TABLE_LIST structure pointer (owner of TABLE) tablenr - table number */ + inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) { table->used_fields= 0; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 41bd9706fc3..d6b1426ed35 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -210,6 +210,7 @@ const char *sql_mode_names[] = { "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", + "NO_DIR_IN_CREATE", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI", "NO_AUTO_VALUE_ON_ZERO", NullS @@ -1119,7 +1120,14 @@ static void server_init(void) IPaddr.sin_family = AF_INET; IPaddr.sin_addr.s_addr = my_bind_addr; IPaddr.sin_port = (unsigned short) htons((unsigned short) mysqld_port); + +#ifndef __WIN__ + /* + We should not use SO_REUSEADDR on windows as this would enable a + user to open two mysqld servers with the same TCP/IP port. + */ (void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg)); +#endif /* __WIN__ */ if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr), sizeof(IPaddr)) < 0) { @@ -2050,7 +2058,10 @@ static int init_common_variables(const char *conf_file_name, int argc, max_connections,table_cache_size)); sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size); } + open_files_limit= files; } +#else + open_files_limit= 0; /* Can't set or detect limit */ #endif unireg_init(opt_specialflag); /* Set up extern variabels */ init_errmessage(); /* Read error messages from file */ @@ -3104,6 +3115,12 @@ extern "C" pthread_handler_decl(handle_connections_sockets, } if (sock == unix_sock) thd->host=(char*) localhost; +#ifdef __WIN__ + /* Set default wait_timeout */ + ulong wait_timeout= global_system_variables.net_wait_timeout * 1000; + (void) setsockopt(new_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&wait_timeout, + sizeof(wait_timeout)); +#endif create_new_thread(thd); } @@ -4196,7 +4213,7 @@ replicating a LOAD DATA INFILE command.", "Max packetlength to send/receive from to server.", (gptr*) &global_system_variables.max_allowed_packet, (gptr*) &max_system_variables.max_allowed_packet, 0, GET_ULONG, - REQUIRED_ARG, 1024*1024L, 80, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, + REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", (gptr*) &max_binlog_cache_size, (gptr*) &max_binlog_cache_size, 0, @@ -5563,6 +5580,19 @@ static void fix_paths(void) } +/* + set how many open files we want to be able to handle + + SYNOPSIS + set_maximum_open_files() + max_file_limit Files to open + + NOTES + The request may not fulfilled becasue of system limitations + + RETURN + Files available to open +*/ #ifdef SET_RLIMIT_NOFILE static uint set_maximum_open_files(uint max_file_limit) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index f12705572d6..d39fca595ac 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -240,10 +240,12 @@ my_bool net_flush(NET *net) *****************************************************************************/ /* -** Write a logical packet with packet header -** Format: Packet length (3 bytes), packet number(1 byte) -** When compression is used a 3 byte compression length is added -** NOTE: If compression is used the original package is modified! + Write a logical packet with packet header + Format: Packet length (3 bytes), packet number(1 byte) + When compression is used a 3 byte compression length is added + + NOTE + If compression is used the original package is modified! */ my_bool @@ -364,8 +366,8 @@ net_write_command(NET *net,uchar command, The cached buffer can be sent as it is with 'net_flush()'. In this code we have to be careful to not send a packet longer than - MAX_PACKET_LENGTH to net_real_write() if we are using the compressed protocol - as we store the length of the compressed packet in 3 bytes. + MAX_PACKET_LENGTH to net_real_write() if we are using the compressed + protocol as we store the length of the compressed packet in 3 bytes. RETURN 0 ok @@ -483,6 +485,7 @@ net_real_write(NET *net,const char *packet,ulong len) thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff); #else alarmed=0; + vio_timeout(net->vio, net->write_timeout); #endif /* NO_ALARM */ pos=(char*) packet; end=pos+len; @@ -674,6 +677,8 @@ my_real_read(NET *net, ulong *complen) #ifndef NO_ALARM if (net_blocking) thr_alarm(&alarmed,net->read_timeout,&alarm_buff); +#else + vio_timeout(net->vio, net->read_timeout); #endif /* NO_ALARM */ pos = net->buff + net->where_b; /* net->packet -4 */ @@ -877,20 +882,23 @@ my_net_read(NET *net) { /* We are using the compressed protocol */ - ulong buf_length= net->buf_length; - ulong start_of_packet= net->buf_length - net->remain_in_buf; - ulong first_packet_offset=start_of_packet; + ulong buf_length; + ulong start_of_packet; + ulong first_packet_offset; uint read_length, multi_byte_packet=0; if (net->remain_in_buf) { + buf_length= net->buf_length; // Data left in old packet + first_packet_offset= start_of_packet= (net->buf_length - + net->remain_in_buf); /* Restore the character that was overwritten by the end 0 */ - net->buff[start_of_packet]=net->save_char; + net->buff[start_of_packet]= net->save_char; } else { /* reuse buffer, as there is nothing in it that we need */ - buf_length=start_of_packet=first_packet_offset=0; + buf_length= start_of_packet= first_packet_offset= 0; } for (;;) { diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 23fb36c0c91..947c930b2f4 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -341,8 +341,8 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, DBUG_RETURN(0); if (!(select= new SQL_SELECT)) { - *error= 1; - DBUG_RETURN(0); /* purecov: inspected */ + *error= 1; // out of memory + DBUG_RETURN(0); /* purecov: inspected */ } select->read_tables=read_tables; select->const_tables=const_tables; @@ -456,15 +456,17 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) SEL_ARG *tmp; if (type != KEY_RANGE) { - tmp=new SEL_ARG(type); + if(!(tmp=new SEL_ARG(type))) + return 0; // out of memory tmp->prev= *next_arg; // Link into next/prev chain (*next_arg)->next=tmp; (*next_arg)= tmp; } else { - tmp=new SEL_ARG(field,part, min_value,max_value, - min_flag, max_flag, maybe_flag); + if(!(tmp=new SEL_ARG(field,part, min_value,max_value, + min_flag, max_flag, maybe_flag))) + return 0; // out of memory tmp->parent=new_parent; tmp->next_key_part=next_key_part; if (left != &null_element) @@ -762,6 +764,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) while ((item=li++)) { SEL_TREE *new_tree=get_mm_tree(param,item); + if(current_thd->fatal_error) + DBUG_RETURN(0); // out of memory tree=tree_and(param,tree,new_tree); if (tree && tree->type == SEL_TREE::IMPOSSIBLE) break; @@ -777,7 +781,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) { SEL_TREE *new_tree=get_mm_tree(param,item); if (!new_tree) - DBUG_RETURN(0); + DBUG_RETURN(0); // out of memory tree=tree_or(param,tree,new_tree); if (!tree || tree->type == SEL_TREE::ALWAYS) break; @@ -793,18 +797,16 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) DBUG_RETURN(new SEL_TREE(SEL_TREE::ALWAYS)); DBUG_RETURN(new SEL_TREE(SEL_TREE::IMPOSSIBLE)); } + table_map ref_tables=cond->used_tables(); - if (ref_tables & ~(param->prev_tables | param->read_tables | - param->current_table)) - DBUG_RETURN(0); // Can't be calculated yet if (cond->type() != Item::FUNC_ITEM) { // Should be a field - if (ref_tables & param->current_table) + if ((ref_tables & param->current_table) || + (ref_tables & ~(param->prev_tables | param->read_tables))) DBUG_RETURN(0); DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); } - if (!(ref_tables & param->current_table)) - DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true + Item_func *cond_func= (Item_func*) cond; if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_RETURN(0); // Can't be calculated @@ -815,12 +817,13 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) { Field *field=((Item_field*) (cond_func->arguments()[0]))->field; Item_result cmp_type=field->cmp_type(); - tree= get_mm_parts(param,field,Item_func::GE_FUNC, - cond_func->arguments()[1],cmp_type); - DBUG_RETURN(tree_and(param,tree, + DBUG_RETURN(tree_and(param, + get_mm_parts(param, field, + Item_func::GE_FUNC, + cond_func->arguments()[1], cmp_type), get_mm_parts(param, field, Item_func::LE_FUNC, - cond_func->arguments()[2],cmp_type))); + cond_func->arguments()[2], cmp_type))); } DBUG_RETURN(0); } @@ -846,6 +849,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) DBUG_RETURN(0); // Can't optimize this IN } + if (ref_tables & ~(param->prev_tables | param->read_tables | + param->current_table)) + DBUG_RETURN(0); // Can't be calculated yet + if (!(ref_tables & param->current_table)) + DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true + /* check field op const */ /* btw, ft_func's arguments()[0] isn't FIELD_ITEM. SerG*/ if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM) @@ -877,14 +886,15 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) static SEL_TREE * -get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value, - Item_result cmp_type) +get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, + Item *value, Item_result cmp_type) { DBUG_ENTER("get_mm_parts"); if (field->table != param->table) DBUG_RETURN(0); - KEY_PART *key_part = param->key_parts,*end=param->key_parts_end; + KEY_PART *key_part = param->key_parts; + KEY_PART *end = param->key_parts_end; SEL_TREE *tree=0; if (value && value->used_tables() & ~(param->prev_tables | param->read_tables)) @@ -894,8 +904,8 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value, if (field->eq(key_part->field)) { SEL_ARG *sel_arg=0; - if (!tree) - tree=new SEL_TREE(); + if (!tree && !(tree=new SEL_TREE())) + DBUG_RETURN(0); // out of memory if (!value || !(value->used_tables() & ~param->read_tables)) { sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value); @@ -907,8 +917,11 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value, DBUG_RETURN(tree); } } - else - sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY);// This key may be used later + else { + // This key may be used later + if(!(sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY))) + DBUG_RETURN(0); // out of memory + } sel_arg->part=(uchar) key_part->part; tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg); } @@ -995,9 +1008,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, DBUG_RETURN(0); if (!maybe_null) // Not null field DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0); - tree=new SEL_ARG(field,is_null_string,is_null_string); - if (!tree) - DBUG_RETURN(0); + if (!(tree=new SEL_ARG(field,is_null_string,is_null_string))) + DBUG_RETURN(0); // out of memory if (type == Item_func::ISNOTNULL_FUNC) { tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ @@ -1035,7 +1047,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, field->get_key_image(str+maybe_null,key_part->part_length, field->charset(),key_part->image_type); if (!(tree=new SEL_ARG(field,str,str))) - DBUG_RETURN(0); + DBUG_RETURN(0); // out of memory switch (type) { case Item_func::LT_FUNC: @@ -1475,7 +1487,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) SEL_ARG *key2_next=key2->next; if (key2_shared) { - key2=new SEL_ARG(*key2); + if(!(key2=new SEL_ARG(*key2))) + return 0; // out of memory key2->increment_use_count(key1->use_count+1); key2->next=key2_next; // New copy of key2 } @@ -2319,16 +2332,16 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, } /* Get range for retrieving rows in QUICK_SELECT::get_next */ - range= new QUICK_RANGE(param->min_key, - (uint) (tmp_min_key - param->min_key), - param->max_key, - (uint) (tmp_max_key - param->max_key), - flag); + if(!(range= new QUICK_RANGE(param->min_key, + (uint) (tmp_min_key - param->min_key), + param->max_key, + (uint) (tmp_max_key - param->max_key), + flag))) + return 1; // out of memory + set_if_bigger(quick->max_used_key_length,range->min_length); set_if_bigger(quick->max_used_key_length,range->max_length); set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1); - if (!range) // Not enough memory - return 1; quick->ranges.push_back(range); end: @@ -2389,17 +2402,17 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref) uint part; if (!quick) - return 0; + return 0; /* no ranges found */ if (cp_buffer_from_ref(ref)) { if (current_thd->is_fatal_error) - return 0; // End of memory + return 0; // out of memory return quick; // empty range } QUICK_RANGE *range= new QUICK_RANGE(); if (!range) - goto err; + goto err; // out of memory range->min_key=range->max_key=(char*) ref->key_buff; range->min_length=range->max_length=ref->key_length; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index e9c3b1ed0b0..402a37efc37 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -250,6 +250,18 @@ static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg) /* Impossible */ } +/* + Before 4.0.15 we had a member of THD called log_pos, it was meant for + failsafe replication code in repl_failsafe.cc which is disabled until + it is reworked. Event's log_pos used to be preserved through + log-slave-updates to make code in repl_failsafe.cc work (this + function, SHOW NEW MASTER); but on the other side it caused unexpected + values in Exec_master_log_pos in A->B->C replication setup, + synchronization problems in master_pos_wait(), ... So we + (Dmitri & Guilhem) removed it. + + So for now this function is broken. +*/ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg) { @@ -415,6 +427,9 @@ static Slave_log_event* find_slave_event(IO_CACHE* log, return (Slave_log_event*)ev; } +/* + This function is broken now. See comment for translate_master(). + */ int show_new_master(THD* thd) { diff --git a/sql/set_var.cc b/sql/set_var.cc index 91583759c70..cce9298c4ac 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -615,13 +615,6 @@ struct show_var_st init_vars[]= { {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, {sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS}, - {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, - {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, - {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, -#ifdef HAVE_REPLICATION - {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS}, -#endif - {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, #ifdef HAVE_QUERY_CACHE {sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS}, {sys_query_cache_min_res_unit.name, (char*) &sys_query_cache_min_res_unit, @@ -629,6 +622,13 @@ struct show_var_st init_vars[]= { {sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS}, {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS}, #endif /* HAVE_QUERY_CACHE */ + {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, + {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, + {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, +#ifdef HAVE_REPLICATION + {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS}, +#endif + {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, #ifdef HAVE_SMEM {"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL}, {"shared_memory_base_name", (char*) &shared_memory_base_name, SHOW_CHAR_PTR}, @@ -845,10 +845,12 @@ void fix_max_relay_log_size(THD *thd, enum_var_type type) bool sys_var_long_ptr::update(THD *thd, set_var *var) { ulonglong tmp= var->value->val_int(); + pthread_mutex_lock(&LOCK_global_system_variables); if (option_limits) *value= (ulong) getopt_ull_limit_value(tmp, option_limits); else *value= (ulong) tmp; + pthread_mutex_unlock(&LOCK_global_system_variables); return 0; } @@ -862,17 +864,21 @@ void sys_var_long_ptr::set_default(THD *thd, enum_var_type type) bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var) { ulonglong tmp= var->value->val_int(); + pthread_mutex_lock(&LOCK_global_system_variables); if (option_limits) *value= (ulonglong) getopt_ull_limit_value(tmp, option_limits); else *value= (ulonglong) tmp; + pthread_mutex_unlock(&LOCK_global_system_variables); return 0; } void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type) { + pthread_mutex_lock(&LOCK_global_system_variables); *value= (ulonglong) option_limits->def_value; + pthread_mutex_unlock(&LOCK_global_system_variables); } @@ -1164,9 +1170,21 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) case SHOW_LONG: return new Item_uint((int32) *(ulong*) value_ptr(thd, var_type, base)); case SHOW_LONGLONG: - return new Item_int(*(longlong*) value_ptr(thd, var_type, base)); + { + longlong value; + pthread_mutex_lock(&LOCK_global_system_variables); + value= *(longlong*) value_ptr(thd, var_type, base); + pthread_mutex_unlock(&LOCK_global_system_variables); + return new Item_int(value); + } case SHOW_HA_ROWS: - return new Item_int((longlong) *(ha_rows*) value_ptr(thd, var_type, base)); + { + ha_rows value; + pthread_mutex_lock(&LOCK_global_system_variables); + value= *(ha_rows*) value_ptr(thd, var_type, base); + pthread_mutex_unlock(&LOCK_global_system_variables); + return new Item_int((longlong) value); + } case SHOW_MY_BOOL: return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1); case SHOW_CHAR: diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 99a940e62ab..b1b607ca6e3 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -219,26 +219,26 @@ "Não pode acrescentar uma restrição de chave estrangeira", "Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou", "Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou", -"Erro connectando para o master: %-.128s", +"Erro conectando com o master: %-.128s", "Erro rodando consulta no master: %-.128s", "Erro quando executando comando %s: %-.128s", "Uso errado de %s e %s", -"Os comandos SELECT usados têm diferentes números de colunas", -"Não pode executar a consulta porque você tem um conflitante travamento de leitura", -"Combinação de tabelas transacionais e não transacionais está desativada", +"Os comandos SELECT usados têm diferente número de colunas", +"Não posso executar a consulta porque você tem um conflito de travamento de leitura", +"Mistura de tabelas transacional e não-transacional está desabilitada", "Opção '%s' usada duas vezes no comando", -"Usuário '%-.64s' há excedido o '%s' de recursos (atual valor: %ld)", -"Acesso negado. Você necessita o privilégio %-.128s para essa operação", +"Usuário '%-.64s' tem excedido o '%s' recurso (atual valor: %ld)", +"Acesso negado. Você precisa o privilégio %-.128s para essa operação", "Variável '%-.64s' é uma LOCAL variável e não pode ser usada com SET GLOBAL", -"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL", -"Variável '%-.64s' não tem um valor default (padrão)", +"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL", +"Variável '%-.64s' não tem um valor padrão", "Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'", -"Tipo de argumento errado para a variável '%-.64s'", +"Tipo errado de argumento para variável '%-.64s'", "Variável '%-.64s' somente pode ser configurada, não lida", -"Uso/localização errada de '%s'", +"Errado uso/colocação de '%s'", "Esta versão de MySQL não suporta ainda '%s'", -"Obteve fatal error %d: '%-.128s' a partir do master quando lendo dados do binary log", -"Slave SQL thread ignored the query because of replicate-*-table rules", +"Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log", +"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela" "Definição errada da chave estrangeira para '%-.64s': %s", "Referência da chave e referência da tabela não coincidem", "Error de cardinalidade (mais/menos que %d colunas)", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index df18b8bf7f0..2b3a6a042fc 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -223,23 +223,23 @@ "Error de coneccion a master: %-128s", "Error executando el query en master: %-128%", "Error de %s: %-128%", -"Wrong usage of %s and %s", -"The used SELECT statements have a different number of columns", -"Can't execute the query because you have a conflicting read lock", -"Mixing of transactional and non-transactional tables is disabled", -"Option '%s' used twice in statement", -"User '%-.64s' has exceeded the '%s' resource (current value: %ld)", -"Access denied. You need the %-.128s privilege for this operation", -"Variable '%-.64s' is a LOCAL variable and can't be used with SET GLOBAL", -"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL", -"Variable '%-.64s' doesn't have a default value", -"Variable '%-.64s' can't be set to the value of '%-.64s'", -"Wrong argument type to variable '%-.64s'", -"Variable '%-.64s' can only be set, not read", -"Wrong usage/placement of '%s'", -"This version of MySQL doesn't yet support '%s'", -"Got fatal error %d: '%-.128s' from master when reading data from binary log", -"Slave SQL thread ignored the query because of replicate-*-table rules", +"Equivocado uso de %s y %s", +"El comando SELECT usado tiene diferente número de columnas", +"No puedo ejecutar el query porque usted tiene conflicto de traba de lectura", +"Mezla de transancional y no-transancional tablas está deshabilitada", +"Opción '%s' usada dos veces en el comando", +"Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)", +"Acceso negado. Usted necesita el privilegio %-.128s para esta operación", +"Variable '%-.64s' es una LOCAL variable y no puede ser usada con SET GLOBAL", +"Variable '%-.64s' es una GLOBAL variable y no puede ser configurada con SET GLOBAL", +"Variable '%-.64s' no tiene un valor patrón", +"Variable '%-.64s' no puede ser configurada para el valor de '%-.64s'", +"Tipo de argumento equivocado para variable '%-.64s'", +"Variable '%-.64s' solamente puede ser configurada, no leída", +"Equivocado uso/colocación de '%s'", +"Esta versión de MySQL no soporta todavia '%s'", +"Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log", +"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla" "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/slave.cc b/sql/slave.cc index d5da8325c93..9e03856e284 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1505,11 +1505,10 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) DBUG_ENTER("wait_for_relay_log_space"); pthread_mutex_lock(&rli->log_space_lock); - save_proc_info = thd->proc_info; - thd->proc_info = "Waiting for relay log space to free"; save_proc_info= thd->enter_cond(&rli->log_space_cond, &rli->log_space_lock, - "Waiting for relay log space to free"); + "\ +Waiting for the SQL slave thread to free enough relay log space"); while (rli->log_space_limit < rli->log_space_total && !(slave_killed=io_slave_killed(thd,mi)) && !rli->ignore_log_space_limit) @@ -2058,7 +2057,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, DBUG_PRINT("info",("Waiting for master update")); const char* msg = thd->enter_cond(&data_cond, &data_lock, - "Waiting for master update"); + "Waiting for the SQL slave thread to \ +advance position"); /* We are going to pthread_cond_(timed)wait(); if the SQL thread stops it will wake us up. @@ -2125,7 +2125,13 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) thd->master_access= ~0; thd->priv_user = 0; thd->slave_thread = 1; - thd->options = (((opt_log_slave_updates) ? OPTION_BIN_LOG:0) | OPTION_AUTO_IS_NULL) ; + thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) | + OPTION_AUTO_IS_NULL; + /* + It's nonsense to constraint the slave threads with max_join_size; if a + query succeeded on master, we HAVE to execute it. + */ + thd->variables.max_join_size= HA_POS_ERROR; thd->client_capabilities = CLIENT_LOCAL_FILES; thd->real_id=pthread_self(); pthread_mutex_lock(&LOCK_thread_count); @@ -2145,11 +2151,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); #endif - if (thd->variables.max_join_size == HA_POS_ERROR) - thd->options |= OPTION_BIG_SELECTS; - if (thd_type == SLAVE_THD_SQL) - thd->proc_info= "Waiting for the next event in slave queue"; + thd->proc_info= "Waiting for the next event in relay log"; else thd->proc_info= "Waiting for master update"; thd->version=refresh_version; @@ -2390,7 +2393,6 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) if (!ev->when) ev->when = time(NULL); ev->thd = thd; - thd->log_pos = ev->log_pos; exec_res = ev->exec_event(rli); DBUG_ASSERT(rli->sql_thd==thd); delete ev; @@ -2398,7 +2400,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) } else { - sql_print_error("\ + slave_print_error(rli, 0, "\ Could not parse relay log event entry. The possible reasons are: the master's \ binary log is corrupted (you can check this by running 'mysqlbinlog' on the \ binary log), the slave's relay log is corrupted (you can check this by running \ @@ -2473,7 +2475,7 @@ slave_begin: } - thd->proc_info = "connecting to master"; + thd->proc_info = "Connecting to master"; // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\ @@ -2520,7 +2522,7 @@ dump"); goto err; } - thd->proc_info = "Waiting to reconnect after a failed dump request"; + thd->proc_info= "Waiting to reconnect after a failed binlog dump request"; end_server(mysql); /* First time retry immediately, assuming that we can recover @@ -2541,7 +2543,7 @@ dump"); goto err; } - thd->proc_info = "Reconnecting after a failed dump request"; + thd->proc_info = "Reconnecting after a failed binlog dump request"; if (!suppress_warnings) sql_print_error("Slave I/O thread: failed dump request, \ reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME, @@ -2560,7 +2562,13 @@ after reconnect"); while (!io_slave_killed(thd,mi)) { bool suppress_warnings= 0; - thd->proc_info = "Reading master update"; + /* + We say "waiting" because read_event() will wait if there's nothing to + read. But if there's something to read, it will not wait. The important + thing is to not confuse users by saying "reading" whereas we're in fact + receiving nothing. + */ + thd->proc_info = "Waiting for master to send event"; ulong event_len = read_event(mysql, mi, &suppress_warnings); if (io_slave_killed(thd,mi)) { @@ -2587,7 +2595,7 @@ max_allowed_packet", mysql_error(mysql)); goto err; } - thd->proc_info = "Waiting to reconnect after a failed read"; + thd->proc_info = "Waiting to reconnect after a failed master event read"; end_server(mysql); if (retry_count++) { @@ -2603,7 +2611,7 @@ max_allowed_packet", reconnect after a failed read"); goto err; } - thd->proc_info = "Reconnecting after a failed read"; + thd->proc_info = "Reconnecting after a failed master event read"; if (!suppress_warnings) sql_print_error("Slave I/O thread: Failed reading log event, \ reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME, @@ -2620,7 +2628,7 @@ reconnect done to recover from failed read"); } // if (event_len == packet_error) retry_count=0; // ok event, reset retry counter - thd->proc_info = "Queueing event from master"; + thd->proc_info = "Queueing master event to the relay log"; if (queue_event(mi,(const char*)mysql->net.read_pos + 1, event_len)) { @@ -2802,7 +2810,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, while (!sql_slave_killed(thd,rli)) { - thd->proc_info = "Processing master log event"; + thd->proc_info = "Reading event from the relay log"; DBUG_ASSERT(rli->sql_thd == thd); THD_CHECK_SENTRY(thd); if (exec_relay_log_event(thd,rli)) @@ -2834,6 +2842,12 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun /* When master_pos_wait() wakes up it will check this and terminate */ rli->slave_running= 0; + /* + Going out of the transaction. Necessary to mark it, in case the user + restarts replication from a non-transactional statement (with CHANGE + MASTER). + */ + rli->inside_transaction= 0; /* Wake up master_pos_wait() */ pthread_mutex_unlock(&rli->data_lock); DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions")); @@ -2909,7 +2923,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) in the loop */ { - Append_block_log_event aev(thd,0,0,0); + Append_block_log_event aev(thd,0,0,0,0); for (;;) { @@ -2922,7 +2936,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) if (unlikely(!num_bytes)) /* eof */ { net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */ - Execute_load_log_event xev(thd,0); + Execute_load_log_event xev(thd,0,0); xev.log_pos = mi->master_log_pos; if (unlikely(mi->rli.relay_log.append(&xev))) { @@ -3049,6 +3063,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf, tmp_buf[event_len]=0; // Create_file constructor wants null-term buffer buf = (const char*)tmp_buf; } + /* + This will transform LOAD_EVENT into CREATE_FILE_EVENT, ask the master to + send the loaded file, and write it to the relay log in the form of + Append_block/Exec_load (the SQL thread needs the data, as that thread is not + connected to the master). + */ Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg, 1 /*old format*/ ); if (unlikely(!ev)) @@ -3076,6 +3096,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf, inc_pos= 0; break; case CREATE_FILE_EVENT: + /* + Yes it's possible to have CREATE_FILE_EVENT here, even if we're in + queue_old_event() which is for 3.23 events which don't comprise + CREATE_FILE_EVENT. This is because read_log_event() above has just + transformed LOAD_EVENT into CREATE_FILE_EVENT. + */ { /* We come here when and only when tmp_buf != 0 */ DBUG_ASSERT(tmp_buf); @@ -3575,7 +3601,7 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s", pthread_mutex_unlock(&rli->log_space_lock); pthread_cond_broadcast(&rli->log_space_cond); // Note that wait_for_update unlocks lock_log ! - rli->relay_log.wait_for_update(rli->sql_thd); + rli->relay_log.wait_for_update(rli->sql_thd, 1); // re-acquire data lock since we released it earlier pthread_mutex_lock(&rli->data_lock); continue; diff --git a/sql/slave.h b/sql/slave.h index 0cd291a50f8..3afa1723cf1 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -32,6 +32,30 @@ *****************************************************************************/ +/* + MUTEXES in replication: + + LOCK_active_mi: this is meant for multimaster, when we can switch from a + master to another. It protects active_mi. We don't care of it for the moment, + as active_mi never moves (it's created at startup and deleted at shutdown, + and not changed: it always points to the same MASTER_INFO struct), because we + don't have multimaster. So for the moment, mi does not move, and mi->rli does + not either. + + In MASTER_INFO: run_lock, data_lock + run_lock protects all information about the run state: slave_running, and the + existence of the I/O thread (to stop/start it, you need this mutex). + data_lock protects some moving members of the struct: counters (log name, + position) and relay log (MYSQL_LOG object). + + In RELAY_LOG_INFO: run_lock, data_lock + see MASTER_INFO + + In MYSQL_LOG: LOCK_log, LOCK_index of the binlog and the relay log + LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog + (so that you have to update the .index file). +*/ + extern ulong master_retry_count; extern MY_BITMAP slave_error_mask; extern bool use_slave_mask; @@ -43,10 +67,6 @@ extern my_bool opt_log_slave_updates; extern ulonglong relay_log_space_limit; struct st_master_info; -extern "C" { - extern ulong slave_net_timeout; -}; - enum enum_binlog_formats { BINLOG_FORMAT_CURRENT=0, /* 0 is important for easy 'if (mi->old_format)' */ BINLOG_FORMAT_323_LESS_57, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9738c0c5d9e..904080f3745 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -599,6 +599,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, { Vio *vio=thd->net.vio; +#ifdef HAVE_OPENSSL + SSL *ssl= (SSL*) vio->ssl_arg; +#endif /* At this point we know that user is allowed to connect from given host by given username/password pair. Now @@ -624,8 +627,8 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, we should reject connection. */ if (vio_type(vio) == VIO_TYPE_SSL && - SSL_get_verify_result(vio->ssl_) == X509_V_OK && - SSL_get_peer_certificate(vio->ssl_)) + SSL_get_verify_result(ssl) == X509_V_OK && + SSL_get_peer_certificate(ssl)) user_access=acl_user->access; break; case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */ @@ -636,27 +639,27 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, use. */ if (vio_type(vio) != VIO_TYPE_SSL || - SSL_get_verify_result(vio->ssl_) != X509_V_OK) + SSL_get_verify_result(ssl) != X509_V_OK) break; if (acl_user->ssl_cipher) { DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'", - acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))); - if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))) + acl_user->ssl_cipher,SSL_get_cipher(ssl))); + if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl))) user_access=acl_user->access; else { if (global_system_variables.log_warnings) sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'", acl_user->ssl_cipher, - SSL_get_cipher(vio->ssl_)); + SSL_get_cipher(ssl)); user_access=NO_ACCESS; break; } } /* Prepare certificate (if exists) */ DBUG_PRINT("info",("checkpoint 1")); - X509* cert=SSL_get_peer_certificate(vio->ssl_); + X509* cert=SSL_get_peer_certificate(ssl); DBUG_PRINT("info",("checkpoint 2")); /* If X509 issuer is speified, we check it... */ if (acl_user->x509_issuer) @@ -2445,7 +2448,7 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, { my_printf_error(ER_WRONG_USAGE, ER(ER_WRONG_USAGE), MYF(0), "DB GRANT","GLOBAL PRIVILEGES"); - result= -1; + result= 1; } } } @@ -3172,6 +3175,8 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL))) global.append("ALL PRIVILEGES",14); + else if (!(table_access & ~GRANT_ACL)) + global.append("USAGE",5); else { int found= 0; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 763408dc5c2..e743c3ecdb8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -133,7 +133,6 @@ THD::THD():user_time(0), is_fatal_error(0), where="field list"; server_id = ::server_id; slave_net = 0; - log_pos = 0; command=COM_CONNECT; set_query_id=1; db_access=NO_ACCESS; diff --git a/sql/sql_class.h b/sql/sql_class.h index e10795c4d9d..9149be9f1ae 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -129,7 +129,7 @@ public: } void set_max_size(ulong max_size_arg); void signal_update() { pthread_cond_broadcast(&update_cond);} - void wait_for_update(THD* thd); + void wait_for_update(THD* thd, bool master_or_slave); void set_need_start_event() { need_start_event = 1; } void init(enum_log_type log_type_arg, enum cache_type io_cache_type_arg, @@ -146,7 +146,7 @@ public: bool write(THD *thd, const char *query, uint query_length, time_t query_start=0); bool write(Log_event* event_info); // binary log write - bool write(THD *thd, IO_CACHE *cache); + bool write(THD *thd, IO_CACHE *cache, bool commit_or_rollback); /* v stands for vector @@ -560,7 +560,6 @@ public: char scramble[SCRAMBLE41_LENGTH+1]; // old scramble is needed to handle old clients char old_scramble[SCRAMBLE_LENGTH+1]; - uint8 query_cache_type; // type of query cache processing bool slave_thread; bool set_query_id,locked,count_cuted_fields,some_tables_deleted; bool last_cuted_field; @@ -580,7 +579,6 @@ public: */ LOG_INFO* current_linfo; NET* slave_net; // network connection from slave -> m. - my_off_t log_pos; /* Used by the sys_var class to store temporary values */ union { @@ -965,7 +963,6 @@ typedef struct st_sort_buffer { SORT_FIELD *sortorder; } SORT_BUFFER; - /* Structure for db & table in sql_yacc */ class Table_ident :public Sql_alloc diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 947205949f1..66af0298f3e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1448,6 +1448,8 @@ void select_insert::send_error(uint errcode,const char *err) table->file->has_transactions()); mysql_bin_log.write(&qinfo); } + if (!table->tmp_table) + thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; } if (info.copied || info.deleted) query_cache_invalidate3(thd, table, 1); @@ -1468,7 +1470,11 @@ bool select_insert::send_eof() */ if (info.copied || info.deleted) + { query_cache_invalidate3(thd, table, 1); + if (!(table->file->has_transactions() || table->tmp_table)) + thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; + } if (last_insert_id) thd->insert_id(last_insert_id); // For binary log diff --git a/sql/sql_load.cc b/sql/sql_load.cc index d030eaf617c..8820629c73f 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -171,7 +171,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else #endif { - read_file_from_client=0; #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS ex->file_name+=dirname_length(ex->file_name); #endif @@ -311,7 +310,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, which is nonsense. */ read_info.end_io_cache(); - Delete_file_log_event d(thd, log_delayed); + Delete_file_log_event d(thd, db, log_delayed); mysql_bin_log.write(&d); } } @@ -343,7 +342,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, read_info.end_io_cache(); // make sure last block gets logged if (lf_info.wrote_create_file) { - Execute_load_log_event e(thd, log_delayed); + Execute_load_log_event e(thd, db, log_delayed); mysql_bin_log.write(&e); } } @@ -806,9 +805,13 @@ int READ_INFO::read_field() row_end= to; return 0; } - /* Copy the found '"' character */ + /* + The string didn't terminate yet. + Store back next character for the loop + */ PUSH(chr); - chr='"'; + /* copy the found term character to 'to' */ + chr= found_enclosed_char; } else if (chr == field_term_char && found_enclosed_char == INT_MAX) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 33e96cc2776..890334e8c94 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1878,6 +1878,7 @@ mysql_execute_command(THD *thd) { if (check_global_access(thd, REPL_SLAVE_ACL)) goto error; + /* This query don't work now. See comment in repl_failsafe.cc */ #ifndef WORKING_NEW_MASTER net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER"); res= 1; @@ -2678,11 +2679,12 @@ mysql_execute_command(THD *thd) break; case SQLCOM_SHOW_STATUS: res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars, - OPT_GLOBAL); + OPT_GLOBAL, &LOCK_status); break; case SQLCOM_SHOW_VARIABLES: res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS), - init_vars, lex->option_type); + init_vars, lex->option_type, + &LOCK_global_system_variables); break; case SQLCOM_SHOW_LOGS: #ifdef DONT_ALLOW_SHOW_COMMANDS @@ -3204,7 +3206,16 @@ mysql_execute_command(THD *thd) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (!ha_rollback(thd)) { - if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) + /* + If a non-transactional table was updated, warn; don't warn if this is a + slave thread (because when a slave thread executes a ROLLBACK, it has + been read from the binary log, so it's 100% sure and normal to produce + error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the + slave SQL thread, it would not stop the thread but just be printed in + the error log; but we don't want users to wonder why they have this + message in the error log, so we don't send it. + */ + if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread) send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0); else send_ok(thd); @@ -3216,7 +3227,7 @@ mysql_execute_command(THD *thd) case SQLCOM_ROLLBACK_TO_SAVEPOINT: if (!ha_rollback_to_savepoint(thd, lex->savepoint_name)) { - if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) + if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread) send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0); else send_ok(thd); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 3cdf033c477..2bfc73ae1a1 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -545,7 +545,7 @@ Increase max_allowed_packet on master"; if (!thd->killed) { /* Note that the following call unlocks lock_log */ - mysql_bin_log.wait_for_update(thd); + mysql_bin_log.wait_for_update(thd, 0); } else pthread_mutex_unlock(log_lock); @@ -560,7 +560,7 @@ Increase max_allowed_packet on master"; if (read_packet) { - thd->proc_info = "sending update to slave"; + thd->proc_info = "Sending binlog event to slave"; if (my_net_write(net, (char*)packet->ptr(), packet->length()) ) { errmsg = "Failed on my_net_write()"; @@ -597,7 +597,7 @@ Increase max_allowed_packet on master"; { bool loop_breaker = 0; // need this to break out of the for loop from switch - thd->proc_info = "switching to next log"; + thd->proc_info = "Finished reading one binlog; switching to next binlog"; switch (mysql_bin_log.find_next_log(&linfo, 1)) { case LOG_INFO_EOF: loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); @@ -636,14 +636,14 @@ end: (void)my_close(file, MYF(MY_WME)); send_eof(thd); - thd->proc_info = "waiting to finalize termination"; + thd->proc_info = "Waiting to finalize termination"; pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; err: - thd->proc_info = "waiting to finalize termination"; + thd->proc_info = "Waiting to finalize termination"; end_io_cache(&log); /* Exclude iteration through thread list @@ -903,7 +903,7 @@ int change_master(THD* thd, MASTER_INFO* mi) DBUG_RETURN(1); } - thd->proc_info = "changing master"; + thd->proc_info = "Changing master"; LEX_MASTER_INFO* lex_mi = &thd->lex.mi; // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0)) @@ -969,7 +969,7 @@ int change_master(THD* thd, MASTER_INFO* mi) if (need_relay_log_purge) { relay_log_purge= 1; - thd->proc_info="purging old relay logs"; + thd->proc_info="Purging old relay logs"; if (purge_relay_logs(&mi->rli, thd, 0 /* not only reset, but also reinit */, &errmsg)) @@ -1258,7 +1258,7 @@ int log_loaded_block(IO_CACHE* file) lf_info->last_pos_in_file = file->pos_in_file; if (lf_info->wrote_create_file) { - Append_block_log_event a(lf_info->thd, buffer, block_len, + Append_block_log_event a(lf_info->thd, lf_info->db, buffer, block_len, lf_info->log_delayed); mysql_bin_log.write(&a); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index de6b2ce443f..771a3d701bb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1414,7 +1414,6 @@ JOIN::exec() curr_join->group_list : curr_join->order, curr_join->select_limit, unit->select_limit_cnt)) DBUG_VOID_RETURN; - } } curr_join->having= curr_join->tmp_having; thd->proc_info="Sending data"; @@ -2046,28 +2045,34 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, static void add_key_field(KEY_FIELD **key_fields,uint and_level, - Field *field,bool eq_func,Item *value, + Field *field,bool eq_func,Item **value, uint num_values, table_map usable_tables) { uint exists_optimize= 0; if (!(field->flags & PART_KEY_FLAG)) { // Don't remove column IS NULL on a LEFT JOIN table - if (!eq_func || !value || value->type() != Item::NULL_ITEM || - !field->table->maybe_null || field->null_ptr) + if (!eq_func || (*value)->type() != Item::NULL_ITEM || + !field->table->maybe_null || field->null_ptr) return; // Not a key. Skip it exists_optimize= KEY_OPTIMIZE_EXISTS; } else { table_map used_tables=0; - if (value && ((used_tables=value->used_tables()) & - (field->table->map | RAND_TABLE_BIT))) + bool optimizable=0; + for (uint i=0; i<num_values; i++) + { + used_tables|=(*value)->used_tables(); + if (!((*value)->used_tables() & (field->table->map | RAND_TABLE_BIT))) + optimizable=1; + } + if (!optimizable) return; if (!(usable_tables & field->table->map)) { - if (!eq_func || !value || value->type() != Item::NULL_ITEM || - !field->table->maybe_null || field->null_ptr) + if (!eq_func || (*value)->type() != Item::NULL_ITEM || + !field->table->maybe_null || field->null_ptr) return; // Can't use left join optimize exists_optimize= KEY_OPTIMIZE_EXISTS; } @@ -2078,12 +2083,6 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, field->table->keys_in_use_for_query); stat[0].keys|= possible_keys; // Add possible keys - if (!value) - { // Probably BETWEEN or IN - stat[0].const_keys |= possible_keys; - return; // Can't be used as eq key - } - /* Save the following cases: Field op constant @@ -2092,26 +2091,38 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Field op formula Field IS NULL Field IS NOT NULL + Field BETWEEN ... + Field IN ... */ stat[0].key_dependent|=used_tables; - if (value->const_item()) - stat[0].const_keys |= possible_keys; + bool is_const=1; + for (uint i=0; i<num_values; i++) + is_const&= (*value)->const_item(); + if (is_const) + stat[0].const_keys |= possible_keys; /* We can't always use indexes when comparing a string index to a - number. cmp_type() is checked to allow compare of dates to numbers - */ + number. cmp_type() is checked to allow compare of dates to numbers. + eq_func is NEVER true when num_values > 1 + */ if (!eq_func || field->result_type() == STRING_RESULT && - value->result_type() != STRING_RESULT && - field->cmp_type() != value->result_type()) + (*value)->result_type() != STRING_RESULT && + field->cmp_type() != (*value)->result_type()) return; } } + DBUG_ASSERT(num_values == 1); + /* + For the moment eq_func is always true. This slot is reserved for future + extensions where we want to remembers other things than just eq comparisons + */ + DBUG_ASSERT(eq_func); /* Store possible eq field */ (*key_fields)->field= field; (*key_fields)->eq_func= eq_func; - (*key_fields)->val= value; + (*key_fields)->val= *value; (*key_fields)->level= and_level; (*key_fields)->optimize= exists_optimize; (*key_fields)++; @@ -2160,12 +2171,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, case Item_func::OPTIMIZE_NONE: break; case Item_func::OPTIMIZE_KEY: + // BETWEEN or IN if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) add_key_field(key_fields,*and_level, - ((Item_field*) (cond_func->key_item()->real_item())) - ->field, - 0,(Item*) 0,usable_tables); + ((Item_field*) (cond_func->key_item()->real_item()))->field, 0, + cond_func->arguments()+1, cond_func->argument_count()-1, + usable_tables); break; case Item_func::OPTIMIZE_OP: { @@ -2179,7 +2191,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, ((Item_field*) (cond_func->arguments()[0])->real_item()) ->field, equal_func, - (cond_func->arguments()[1]),usable_tables); + cond_func->arguments()+1, 1, usable_tables); } if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && cond_func->functype() != Item_func::LIKE_FUNC && @@ -2189,7 +2201,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, ((Item_field*) (cond_func->arguments()[1])->real_item()) ->field, equal_func, - (cond_func->arguments()[0]),usable_tables); + cond_func->arguments(),1,usable_tables); } break; } @@ -2198,11 +2210,14 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { + Item *tmp=new Item_null; + if (!tmp) // Should never be true + return; add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[0])->real_item()) ->field, cond_func->functype() == Item_func::ISNULL_FUNC, - new Item_null, usable_tables); + &tmp, 1, usable_tables); } break; } @@ -3992,7 +4007,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father, static void -propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level, +propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father, COND *cond) { if (cond->type() == Item::COND_ITEM) @@ -4018,7 +4033,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level, cond_cmp->cmp_func->arguments()[1]); } } - else if (and_level != cond && !cond->marker) // In a AND group + else if (and_father != cond && !cond->marker) // In a AND group { if (cond->type() == Item::FUNC_ITEM && (((Item_func*) cond)->functype() == Item_func::EQ_FUNC || @@ -4036,7 +4051,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level, func->arguments()[1]=resolve_const_item(func->arguments()[1], func->arguments()[0]); func->update_used_tables(); - change_cond_ref_to_const(save_list,and_level,and_level, + change_cond_ref_to_const(save_list,and_father,and_father, func->arguments()[0], func->arguments()[1]); } @@ -4045,7 +4060,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level, func->arguments()[0]=resolve_const_item(func->arguments()[0], func->arguments()[1]); func->update_used_tables(); - change_cond_ref_to_const(save_list,and_level,and_level, + change_cond_ref_to_const(save_list,and_father,and_father, func->arguments()[1], func->arguments()[0]); } @@ -8206,7 +8221,7 @@ update_tmptable_sum_func(Item_sum **func_ptr, { Item_sum *func; while ((func= *(func_ptr++))) - func->update_field(0); + func->update_field(); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9084269f486..997dcce55b4 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -791,9 +791,14 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(1); } + if (store_create_info(thd, table, &buffer)) + DBUG_RETURN(-1); + List<Item> field_list; field_list.push_back(new Item_empty_string("Table",NAME_LEN)); - field_list.push_back(new Item_empty_string("Create Table", MAX_BLOB_WIDTH)); + // 1024 is for not to confuse old clients + field_list.push_back(new Item_empty_string("Create Table", + max(buffer.length(),1024))); if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(1); @@ -1017,11 +1022,38 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) } } + +/* Append directory name (if exists) to CREATE INFO */ + +static void append_directory(THD *thd, String *packet, const char *dir_type, + const char *filename) +{ + uint length; + if (filename && !(thd->sql_mode & MODE_NO_DIR_IN_CREATE)) + { + length= dirname_length(filename); + packet->append(' '); + packet->append(dir_type); + packet->append(" DIRECTORY='", 12); + packet->append(filename, length); + packet->append('\''); + } +} + + #define LIST_PROCESS_HOST_LEN 64 static int store_create_info(THD *thd, TABLE *table, String *packet) { + List<Item> field_list; + char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end; + String type(tmp, sizeof(tmp),&my_charset_bin); + Field **ptr,*field; + uint primary_key; + KEY *key_info; + handler *file= table->file; + HA_CREATE_INFO create_info; my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | MODE_ORACLE | MODE_MSSQL | @@ -1037,9 +1069,6 @@ store_create_info(THD *thd, TABLE *table, String *packet) restore_record(table,default_values); // Get empty record - List<Item> field_list; - char tmp[MAX_FIELD_WIDTH]; - String type(tmp, sizeof(tmp),&my_charset_bin); if (table->tmp_table) packet->append("CREATE TEMPORARY TABLE ", 23); else @@ -1047,13 +1076,14 @@ store_create_info(THD *thd, TABLE *table, String *packet) append_identifier(thd,packet, table->real_name, strlen(table->real_name)); packet->append(" (\n", 3); - Field **ptr,*field; for (ptr=table->field ; (field= *ptr); ptr++) { + bool has_default; + uint flags = field->flags; + if (ptr != table->field) packet->append(",\n", 2); - uint flags = field->flags; packet->append(" ", 2); append_identifier(thd,packet,field->field_name, strlen(field->field_name)); packet->append(' '); @@ -1090,9 +1120,9 @@ store_create_info(THD *thd, TABLE *table, String *packet) if (flags & NOT_NULL_FLAG) packet->append(" NOT NULL", 9); - bool has_default = (field->type() != FIELD_TYPE_BLOB && - field->type() != FIELD_TYPE_TIMESTAMP && - field->unireg_check != Field::NEXT_NUMBER); + has_default= (field->type() != FIELD_TYPE_BLOB && + field->type() != FIELD_TYPE_TIMESTAMP && + field->unireg_check != Field::NEXT_NUMBER); if (has_default) { @@ -1122,9 +1152,11 @@ store_create_info(THD *thd, TABLE *table, String *packet) } } - KEY *key_info=table->key_info; - table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); - uint primary_key = table->primary_key; + key_info= table->key_info; + file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); + bzero((char*) &create_info, sizeof(create_info)); + file->update_create_info(&create_info); + primary_key= table->primary_key; for (uint i=0 ; i < table->keys ; i++,key_info++) { @@ -1175,7 +1207,6 @@ store_create_info(THD *thd, TABLE *table, String *packet) table->field[key_part->fieldnr-1]->key_length() && !(key_info->flags & HA_FULLTEXT))) { - char buff[64]; buff[0] = '('; char* end=int10_to_str((long) key_part->length, buff + 1,10); *end++ = ')'; @@ -1189,10 +1220,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) Get possible foreign key definitions stored in InnoDB and append them to the CREATE TABLE statement */ - handler *file = table->file; - char* for_str= file->get_foreign_key_create_info(); - if (for_str) + if ((for_str= file->get_foreign_key_create_info())) { packet->append(for_str, strlen(for_str)); file->free_foreign_key_create_info(for_str); @@ -1203,8 +1232,6 @@ store_create_info(THD *thd, TABLE *table, String *packet) { packet->append(" TYPE=", 6); packet->append(file->table_type()); - char buff[128]; - char* p; if (table->table_charset && !(thd->variables.sql_mode & MODE_MYSQL323) && @@ -1222,21 +1249,22 @@ store_create_info(THD *thd, TABLE *table, String *packet) if (table->min_rows) { packet->append(" MIN_ROWS="); - p = longlong10_to_str(table->min_rows, buff, 10); - packet->append(buff, (uint) (p - buff)); + end= longlong10_to_str(table->min_rows, buff, 10); + packet->append(buff, (uint) (end- buff)); } if (table->max_rows) { packet->append(" MAX_ROWS="); - p = longlong10_to_str(table->max_rows, buff, 10); - packet->append(buff, (uint) (p - buff)); + end= longlong10_to_str(table->max_rows, buff, 10); + packet->append(buff, (uint) (end - buff)); } + if (table->avg_row_length) { packet->append(" AVG_ROW_LENGTH="); - p=longlong10_to_str(table->avg_row_length, buff,10); - packet->append(buff, (uint) (p - buff)); + end= longlong10_to_str(table->avg_row_length, buff,10); + packet->append(buff, (uint) (end - buff)); } if (table->db_create_options & HA_OPTION_PACK_KEYS) @@ -1260,12 +1288,15 @@ store_create_info(THD *thd, TABLE *table, String *packet) } if (file->raid_type) { - char buff[100]; - sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld", - my_raid_type(file->raid_type), file->raid_chunks, - file->raid_chunksize/RAID_BLOCK_SIZE); - packet->append(buff); + uint length; + length= my_snprintf(buff,sizeof(buff), + " RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld", + my_raid_type(file->raid_type), file->raid_chunks, + file->raid_chunksize/RAID_BLOCK_SIZE); + packet->append(buff, length); } + append_directory(thd, packet, "DATA", create_info.data_file_name); + append_directory(thd, packet, "INDEX", create_info.index_file_name); } DBUG_RETURN(0); } @@ -1522,7 +1553,8 @@ err: int mysqld_show(THD *thd, const char *wild, show_var_st *variables, - enum enum_var_type value_type) + enum enum_var_type value_type, + pthread_mutex_t *mutex) { char buff[1024]; List<Item> field_list; @@ -1536,8 +1568,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, DBUG_RETURN(1); /* purecov: inspected */ null_lex_str.str= 0; // For sys_var->value_ptr() - /* pthread_mutex_lock(&THR_LOCK_keycache); */ - pthread_mutex_lock(&LOCK_status); + pthread_mutex_lock(mutex); for (; variables->name; variables++) { if (!(wild && wild[0] && wild_case_compare(system_charset_info, @@ -1625,83 +1656,83 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_SSL_CTX_SESS_ACCEPT: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : SSL_CTX_sess_accept(ssl_acceptor_fd-> - ssl_context_)), + ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_ACCEPT_GOOD: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : SSL_CTX_sess_accept_good(ssl_acceptor_fd-> - ssl_context_)), + ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_CONNECT_GOOD: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : SSL_CTX_sess_connect_good(ssl_acceptor_fd-> - ssl_context_)), + ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)), + SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context_)), + SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_CB_HITS: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : SSL_CTX_sess_cb_hits(ssl_acceptor_fd-> - ssl_context_)), + ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_HITS: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : SSL_CTX_sess_hits(ssl_acceptor_fd-> - ssl_context_)), + ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_CACHE_FULL: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : SSL_CTX_sess_cache_full(ssl_acceptor_fd-> - ssl_context_)), + ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_MISSES: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : SSL_CTX_sess_misses(ssl_acceptor_fd-> - ssl_context_)), + ssl_context)), buff, 10); break; case SHOW_SSL_CTX_SESS_TIMEOUTS: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)), + SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)), buff,10); break; case SHOW_SSL_CTX_SESS_NUMBER: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)), + SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)), buff,10); break; case SHOW_SSL_CTX_SESS_CONNECT: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)), + SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)), buff,10); break; case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)), + SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)), buff,10); break; case SHOW_SSL_CTX_GET_VERIFY_MODE: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)), + SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)), buff,10); break; case SHOW_SSL_CTX_GET_VERIFY_DEPTH: end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)), + SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)), buff,10); break; case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE: @@ -1711,7 +1742,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, end= pos+4; break; } - switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_)) + switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context)) { case SSL_SESS_CACHE_OFF: pos= "OFF"; @@ -1739,40 +1770,50 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, break; /* First group - functions relying on SSL */ case SHOW_SSL_GET_VERSION: - pos= thd->net.vio->ssl_ ? SSL_get_version(thd->net.vio->ssl_) : ""; + pos= (thd->net.vio->ssl_arg ? + SSL_get_version((SSL*) thd->net.vio->ssl_arg) : ""); end= strend(pos); break; case SHOW_SSL_SESSION_REUSED: - end= int10_to_str((long) (thd->net.vio->ssl_ ? - SSL_session_reused(thd->net.vio->ssl_): - 0), buff, 10); + end= int10_to_str((long) (thd->net.vio->ssl_arg ? + SSL_session_reused((SSL*) thd->net.vio-> + ssl_arg) : + 0), + buff, 10); break; case SHOW_SSL_GET_DEFAULT_TIMEOUT: - end= int10_to_str((long) (thd->net.vio->ssl_ ? - SSL_get_default_timeout(thd->net.vio->ssl_): - 0), buff, 10); + end= int10_to_str((long) (thd->net.vio->ssl_arg ? + SSL_get_default_timeout((SSL*) thd->net.vio-> + ssl_arg) : + 0), + buff, 10); break; case SHOW_SSL_GET_VERIFY_MODE: - end= int10_to_str((long) (thd->net.vio->ssl_ ? - SSL_get_verify_mode(thd->net.vio->ssl_): - 0), buff, 10); + end= int10_to_str((long) (thd->net.vio->ssl_arg ? + SSL_get_verify_mode((SSL*) thd->net.vio-> + ssl_arg): + 0), + buff, 10); break; case SHOW_SSL_GET_VERIFY_DEPTH: - end= int10_to_str((long) (thd->net.vio->ssl_ ? - SSL_get_verify_depth(thd->net.vio->ssl_): - 0), buff, 10); + end= int10_to_str((long) (thd->net.vio->ssl_arg ? + SSL_get_verify_depth((SSL*) thd->net.vio-> + ssl_arg): + 0), + buff, 10); break; case SHOW_SSL_GET_CIPHER: - pos= thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : ""; + pos= (thd->net.vio->ssl_arg ? + SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" ); end= strend(pos); break; case SHOW_SSL_GET_CIPHER_LIST: - if (thd->net.vio->ssl_) + if (thd->net.vio->ssl_arg) { char *to= buff; for (int i=0 ; i++ ;) { - const char *p= SSL_get_cipher_list(thd->net.vio->ssl_,i); + const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i); if (p == NULL) break; to= strmov(to, p); @@ -1796,14 +1837,12 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, goto err; /* purecov: inspected */ } } - pthread_mutex_unlock(&LOCK_status); - /* pthread_mutex_unlock(&THR_LOCK_keycache); */ + pthread_mutex_unlock(mutex); send_eof(thd); DBUG_RETURN(0); err: - pthread_mutex_unlock(&LOCK_status); - /* pthread_mutex_unlock(&THR_LOCK_keycache); */ + pthread_mutex_unlock(mutex); DBUG_RETURN(1); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 37f8d0d7f4f..b1141d15309 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -914,7 +914,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, thd->proc_info="creating table"; + if (thd->sql_mode & MODE_NO_DIR_IN_CREATE) + create_info->data_file_name= create_info->index_file_name= 0; create_info->table_options=db_options; + if (rea_create_table(thd, path, create_info, fields, key_count, key_info_buffer)) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 24497589c73..2b10fe2cd2a 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -123,8 +123,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, DBUG_RETURN(0); prepared= 1; res= 0; - found_rows_for_union= test(first_select_in_union()->options - & OPTION_FOUND_ROWS); + found_rows_for_union= first_select_in_union()->options & OPTION_FOUND_ROWS; TMP_TABLE_PARAM tmp_table_param; result= sel_result; t_and_f= tables_and_fields_initied; @@ -239,7 +238,7 @@ int st_select_lex_unit::exec() { SELECT_LEX *lex_select_save= thd->lex.current_select; SELECT_LEX *select_cursor=first_select_in_union(); - ha_rows add_rows=0; + ulonglong add_rows=0; DBUG_ENTER("st_select_lex_unit::exec"); if (executed && !(dependent || uncacheable)) @@ -263,10 +262,30 @@ int st_select_lex_unit::exec() res= sl->join->reinit(); else { - offset_limit_cnt= sl->offset_limit; - select_limit_cnt= sl->select_limit+sl->offset_limit; + /* Don't use offset for the last union if there is no braces */ + if (sl != lex_sl) + { + offset_limit_cnt= sl->offset_limit; + select_limit_cnt= sl->select_limit+sl->offset_limit; + } + else + { + offset_limit_cnt= 0; + /* + We can't use LIMIT at this stage if we are using ORDER BY for the + whole query + */ + select_limit_cnt= HA_POS_ERROR; + if (! sl->order_list.first) + select_limit_cnt= sl->select_limit+sl->offset_limit; + } if (select_limit_cnt < sl->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit + + /* + When using braces, SQL_CALC_FOUND_ROWS affects the whole query. + We don't calculate found_rows() per union part + */ if (select_limit_cnt == HA_POS_ERROR || sl->braces) sl->options&= ~OPTION_FOUND_ROWS; else @@ -318,11 +337,13 @@ int st_select_lex_unit::exec() thd->lex.current_select= lex_select_save; DBUG_RETURN(res); } + /* Needed for the following test and for records_at_start in next loop */ + table->file->info(HA_STATUS_VARIABLE); if (found_rows_for_union & sl->options) { /* - This is a union without braces. Remember the number of rows that could - also have been part of the result set. + This is a union without braces. Remember the number of rows that + could also have been part of the result set. We get this from the difference of between total number of possible rows and actual rows added to the temporary table. */ @@ -341,7 +362,7 @@ int st_select_lex_unit::exec() List<Item_func_match> empty_list; empty_list.empty(); - if (!thd->is_fatal_error) // Check if EOM + if (!thd->is_fatal_error) // Check if EOM { ulong options= thd->options; thd->lex.current_select= fake_select_lex; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 29138f10989..7430029a5e5 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -600,6 +600,7 @@ multi_update::initialize_tables(JOIN *join) { TABLE *table=table_ref->table; uint cnt= table_ref->shared; + Item_field *If; List<Item> temp_fields= *fields_for_table[cnt]; ORDER group; @@ -623,7 +624,10 @@ multi_update::initialize_tables(JOIN *join) /* ok to be on stack as this is not referenced outside of this func */ Field_string offset(table->file->ref_length, 0, "offset", table, &my_charset_bin); - if (temp_fields.push_front(new Item_field(((Field *) &offset)))) + if (!(If=new Item_field(((Field *) &offset)))) + DBUG_RETURN(1); + If->maybe_null=0; + if (temp_fields.push_front(If)) DBUG_RETURN(1); /* Make an unique key over the first field to avoid duplicated updates */ |