diff options
author | unknown <monty@mashka.mysql.fi> | 2003-09-11 20:31:40 +0300 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2003-09-11 20:31:40 +0300 |
commit | 41824a35338012ff8196eb975f961d5e0f0e2a22 (patch) | |
tree | 1475a169c541e6b7aedb36103dd255fe52fc0517 /sql | |
parent | 07bc35e1d024e5e3b81b131a47878510f0521609 (diff) | |
parent | d32bdcb1bfc274476cdd945e66e00f3ec31253c3 (diff) | |
download | mariadb-git-41824a35338012ff8196eb975f961d5e0f0e2a22.tar.gz |
merge with 4.1 tree
client/mysqltest.c:
Auto merged
include/mysql.h:
Auto merged
libmysql/errmsg.c:
Auto merged
libmysql/libmysql.c:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
sql/field.cc:
Auto merged
sql/item.cc:
Auto merged
sql/item.h:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/share/portuguese/errmsg.txt:
Auto merged
sql/share/spanish/errmsg.txt:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
tests/client_test.c:
Auto merged
Diffstat (limited to 'sql')
39 files changed, 975 insertions, 654 deletions
diff --git a/sql/field.cc b/sql/field.cc index 441dc1ddb60..47e05c3da3b 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/field.h b/sql/field.h index 10d3e671867..fe5141e9d80 100644 --- a/sql/field.h +++ b/sql/field.h @@ -125,6 +125,13 @@ public: { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; } inline bool is_real_null(uint row_offset=0) { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : 0; } + inline bool is_null_in_record(const uchar *record) + { + if (!null_ptr) + return 0; + return test(record[(uint) (null_ptr - (uchar*) table->record[0])] & + null_bit); + } inline void set_null(int row_offset=0) { if (null_ptr) null_ptr[row_offset]|= null_bit; } inline void set_notnull(int row_offset=0) diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index dbed955c0a9..ee1b54e5745 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -1433,6 +1433,8 @@ int ha_berkeley::index_read(byte * buf, const byte * key, } if (key_len == key_info->key_length) { + if (find_flag == HA_READ_AFTER_KEY) + key_info->handler.bdb_return_if_eq= 1; error=read_row(cursor->c_get(cursor, pack_key(&last_key, active_index, key_buff, @@ -1441,6 +1443,7 @@ int ha_berkeley::index_read(byte * buf, const byte * key, (find_flag == HA_READ_KEY_EXACT ? DB_SET : DB_SET_RANGE)), (char*) buf, active_index, &row, (DBT*) 0, 0); + key_info->handler.bdb_return_if_eq= 0; } else { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index d870d0debfd..017151dfca0 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> @@ -1541,82 +1540,6 @@ ha_innobase::close(void) DBUG_RETURN(0); } -/* The following accessor functions should really be inside MySQL code! */ - -/****************************************************************** -Gets field offset for a field in a table. */ -inline -uint -get_field_offset( -/*=============*/ - /* out: offset */ - TABLE* table, /* in: MySQL table object */ - Field* field) /* in: MySQL field object */ -{ - return((uint) (field->ptr - (char*) table->record[0])); -} - -/****************************************************************** -Checks if a field in a record is SQL NULL. Uses the record format -information in table to track the null bit in record. */ -inline -uint -field_in_record_is_null( -/*====================*/ - /* out: 1 if NULL, 0 otherwise */ - TABLE* table, /* in: MySQL table object */ - Field* field, /* in: MySQL field object */ - char* record) /* in: a row in MySQL format */ -{ - int null_offset; - - if (!field->null_ptr) { - - return(0); - } - - null_offset = (uint) ((char*) field->null_ptr - - (char*) table->record[0]); - - if (record[null_offset] & field->null_bit) { - - return(1); - } - - return(0); -} - -/****************************************************************** -Sets a field in a record to SQL NULL. Uses the record format -information in table to track the null bit in record. */ -inline -void -set_field_in_record_to_null( -/*========================*/ - TABLE* table, /* in: MySQL table object */ - Field* field, /* in: MySQL field object */ - char* record) /* in: a row in MySQL format */ -{ - int null_offset; - - null_offset = (uint) ((char*) field->null_ptr - - (char*) table->record[0]); - - record[null_offset] = record[null_offset] | field->null_bit; -} - -/****************************************************************** -Resets SQL NULL bits in a record to zero. */ -inline -void -reset_null_bits( -/*============*/ - TABLE* table, /* in: MySQL table object */ - char* record) /* in: a row in MySQL format */ -{ - bzero(record, table->null_bytes); -} - extern "C" { /***************************************************************** InnoDB uses this function is to compare two data fields for which the @@ -1826,11 +1749,10 @@ ha_innobase::store_key_val_for_row( blob_data = row_mysql_read_blob_ref(&blob_len, (byte*) (record - + (ulint)get_field_offset(table, field)), + + (ulint) field->offset()), (ulint) field->pack_length()); - ut_a(get_field_offset(table, field) - == key_part->offset); + ut_a(field->offset() == key_part->offset); if (blob_len > key_part->length) { blob_len = key_part->length; } @@ -2010,9 +1932,7 @@ build_template( templ->mysql_null_bit_mask = 0; } - templ->mysql_col_offset = (ulint) - get_field_offset(table, field); - + templ->mysql_col_offset = (ulint) field->offset(); templ->mysql_col_len = (ulint) field->pack_length(); templ->type = get_innobase_type_from_mysql_type(field); templ->is_unsigned = (ulint) (field->flags & UNSIGNED_FLAG); @@ -2349,8 +2269,8 @@ calc_row_difference( /* goto skip_field; }*/ - o_ptr = (byte*) old_row + get_field_offset(table, field); - n_ptr = (byte*) new_row + get_field_offset(table, field); + o_ptr = (byte*) old_row + field->offset(); + n_ptr = (byte*) new_row + field->offset(); o_len = field->pack_length(); n_len = field->pack_length(); @@ -2375,13 +2295,11 @@ calc_row_difference( } if (field->null_ptr) { - if (field_in_record_is_null(table, field, - (char*) old_row)) { + if (field->is_null_in_record((uchar*) old_row)) { o_len = UNIV_SQL_NULL; } - if (field_in_record_is_null(table, field, - (char*) new_row)) { + if (field->is_null_in_record((uchar*) new_row)) { n_len = UNIV_SQL_NULL; } } diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index a87bed94484..cec1aefa2d5 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1111,7 +1111,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 851e73f15d2..e14e326792d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -361,7 +361,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) { if (wait_if_global_read_lock(thd, 0)) DBUG_RETURN(1); - mysql_bin_log.write(thd, &thd->transaction.trans_log); + mysql_bin_log.write(thd, &thd->transaction.trans_log, 1); start_waiting_global_read_lock(thd); reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); @@ -445,9 +445,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) { @@ -461,9 +473,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) @@ -488,8 +518,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) @@ -518,6 +564,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); @@ -1054,14 +1107,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 0f799184559..9d34f299a07 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -927,6 +927,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 147c350878e..9f767d502ba 100644 --- a/sql/item.h +++ b/sql/item.h @@ -509,6 +509,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 7460c103550..2179ef1188e 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->is_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 { @@ -1592,7 +1596,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 5ebc4e82f13..fe419745b60 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -190,13 +190,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++) @@ -1418,13 +1420,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 cf554f613d4..86cf19d92f3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -541,6 +541,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 814612cfca8..2b31e15cb4c 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 b2377a96833..78d887782e2 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..91349feec39 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; @@ -988,14 +969,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 +1072,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 +1443,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 +1465,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 +1517,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 +1595,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 +1636,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 +1727,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 +1758,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), log_cs); + 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 +1853,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 +1883,21 @@ 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); + +#ifdef TO_BE_CHECKED_BY_GUILHEM + 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); + } +#endif + 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 +1923,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 +2491,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 +2634,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 +2672,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 +2696,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 +2707,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 +2719,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 +2736,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 +2748,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 +2819,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 +2837,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 +2864,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 +2939,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 +2953,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 +3027,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 +3035,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 +3043,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 +3073,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 c8583c12470..e546243dec9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -209,16 +209,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) @@ -557,7 +558,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); @@ -745,6 +747,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; @@ -962,6 +965,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); @@ -978,6 +987,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 2d82454ad6d..b014929f480 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 @@ -1122,7 +1123,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) { @@ -2053,7 +2061,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 */ @@ -3101,6 +3112,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); } @@ -3806,7 +3823,7 @@ master-ssl", (gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"myisam-recover", OPT_MYISAM_RECOVER, - "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP or FORCE.", + "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", (gptr*) &locked_in_memory, @@ -4197,7 +4214,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, @@ -5565,6 +5582,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..5b1e2c98001 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) @@ -616,6 +618,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, SEL_TREE *tree; KEY_PART *key_parts; PARAM param; + THD *thd= current_thd; /* set up parameter that is passed to all functions */ param.baseflag=basflag; @@ -626,13 +629,13 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, param.keys=0; param.mem_root= &alloc; - current_thd->no_errors=1; // Don't warn about NULL + thd->no_errors=1; // Don't warn about NULL init_sql_alloc(&alloc,2048,0); if (!(param.key_parts = (KEY_PART*) alloc_root(&alloc, sizeof(KEY_PART)* head->key_parts))) { - current_thd->no_errors=0; + thd->no_errors=0; free_root(&alloc,MYF(0)); // Return memory & allocator DBUG_RETURN(0); // Can't use range } @@ -689,7 +692,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, uint keynr= param.real_keynr[idx]; if ((*key)->type == SEL_ARG::MAYBE_KEY || (*key)->maybe_flag) - needed_reg|= (key_map) 1 << keynr; + needed_reg|= (key_map) 1 << keynr; found_records=check_quick_select(¶m, idx, *key); if (found_records != HA_POS_ERROR && found_records > 2 && @@ -713,7 +716,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, param.range_count, found_records)+ (double) found_records / TIME_FOR_COMPARE); - if (read_time > found_read_time) + if (read_time > found_read_time && found_records != HA_POS_ERROR) { read_time=found_read_time; records=found_records; @@ -734,7 +737,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, } free_root(&alloc,MYF(0)); // Return memory & allocator my_pthread_setspecific_ptr(THR_MALLOC,old_root); - current_thd->no_errors=0; + thd->no_errors=0; } DBUG_EXECUTE("info",print_quick(quick,needed_reg);); /* @@ -762,6 +765,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->is_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 +782,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 +798,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 +818,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 +850,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 +887,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 +905,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 +918,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 +1009,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 +1048,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 +1488,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 +2333,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 +2403,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 d9c09c88f0d..8f0e18999b3 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 d07bcd52559..194d91d2c4f 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -620,13 +620,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, @@ -635,6 +628,13 @@ struct show_var_st init_vars[]= { {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS}, {"secure_auth", (char*) &sys_secure_auth, 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}, @@ -851,10 +851,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; } @@ -868,17 +870,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); } @@ -1170,9 +1176,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 95e388c2245..f4a656ba184 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 6cb031c46e3..7e2289694dc 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 dd25fe5e75e..0c8db2fe6cc 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) @@ -2174,7 +2173,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. @@ -2241,7 +2241,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); @@ -2261,11 +2267,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; @@ -2506,7 +2509,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; @@ -2514,7 +2516,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 \ @@ -2589,7 +2591,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',\ @@ -2636,7 +2638,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 @@ -2657,7 +2659,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, @@ -2676,7 +2678,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)) { @@ -2703,7 +2711,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++) { @@ -2719,7 +2727,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, @@ -2736,7 +2744,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)) { @@ -2918,7 +2926,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)) @@ -2950,6 +2958,11 @@ 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). + */ /* Wake up master_pos_wait() */ pthread_mutex_unlock(&rli->data_lock); DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions")); @@ -3025,7 +3038,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 (;;) { @@ -3038,7 +3051,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))) { @@ -3165,6 +3178,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)) @@ -3192,6 +3211,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); @@ -3702,7 +3727,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 f7d288ca64e..7dc33ffcefe 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 a7fe77f6b06..7889a583fde 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -532,13 +532,13 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) /* - Seek ACL entry for a user, check password, SSL cypher, and if - everything is OK, update THD user data and USER_RESOURCES struct. + Seek ACL entry for a user, check password, SSL cypher, and if + everything is OK, update THD user data and USER_RESOURCES struct. - IMPLEMENTATION - This function does not check if the user has any sensible privileges: - only user's existence and validity is checked. - Note, that entire operation is protected by acl_cache_lock. + IMPLEMENTATION + This function does not check if the user has any sensible privileges: + only user's existence and validity is checked. + Note, that entire operation is protected by acl_cache_lock. SYNOPSIS acl_getroot() @@ -555,7 +555,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH 'thd' and 'mqh' are updated on success; other params are IN. - RETURN VALUE + RETURN VALUE 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are updated 1 user not found or authentification failure @@ -566,6 +566,9 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, uint passwd_len) { + ulong user_access= NO_ACCESS; + int res= 1; + ACL_USER *acl_user= 0; DBUG_ENTER("acl_getroot"); if (!initialized) @@ -576,12 +579,10 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, thd->priv_user= (char *) ""; // privileges for *thd->priv_host= '\0'; // the user are unknown thd->master_access= ~NO_ACCESS; // everything is allowed - bzero(mqh, sizeof(*mqh)); + bzero((char*) mqh, sizeof(*mqh)); DBUG_RETURN(0); } - int res= 1; - VOID(pthread_mutex_lock(&acl_cache->lock)); /* @@ -590,32 +591,31 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, but acl_user->user is empty */ - ACL_USER *acl_user= 0; for (uint i=0 ; i < acl_users.elements ; i++) { - ACL_USER *user_i = dynamic_element(&acl_users,i,ACL_USER*); - if (!user_i->user || !strcmp(thd->user, user_i->user)) + ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*); + if (!acl_user_tmp->user || !strcmp(thd->user, acl_user_tmp->user)) { - if (compare_hostname(&user_i->host, thd->host, thd->ip)) + if (compare_hostname(&acl_user_tmp->host, thd->host, thd->ip)) { /* check password: it should be empty or valid */ - if (passwd_len == user_i->salt_len) + if (passwd_len == acl_user_tmp->salt_len) { - if (user_i->salt_len == 0 || - user_i->salt_len == SCRAMBLE_LENGTH && - check_scramble(passwd, thd->scramble, user_i->salt) == 0 || + if (acl_user_tmp->salt_len == 0 || + acl_user_tmp->salt_len == SCRAMBLE_LENGTH && + check_scramble(passwd, thd->scramble, acl_user_tmp->salt) == 0 || check_scramble_323(passwd, thd->scramble, - (ulong *) user_i->salt) == 0) + (ulong *) acl_user_tmp->salt) == 0) { - acl_user= user_i; + acl_user= acl_user_tmp; res= 0; } } else if (passwd_len == SCRAMBLE_LENGTH && - user_i->salt_len == SCRAMBLE_LENGTH_323) + acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323) res= -1; else if (passwd_len == SCRAMBLE_LENGTH_323 && - user_i->salt_len == SCRAMBLE_LENGTH) + acl_user_tmp->salt_len == SCRAMBLE_LENGTH) res= 2; /* linear search complete: */ break; @@ -630,8 +630,11 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, if (acl_user) { /* OK. User found and password checked continue validation */ - thd->master_access= NO_ACCESS; 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 @@ -640,55 +643,55 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, */ switch (acl_user->ssl_type) { case SSL_TYPE_NOT_SPECIFIED: // Impossible - case SSL_TYPE_NONE: /* SSL is not required to connect */ - thd->master_access= acl_user->access; + case SSL_TYPE_NONE: // SSL is not required + user_access= acl_user->access; break; #ifdef HAVE_OPENSSL - case SSL_TYPE_ANY: /* Any kind of SSL is good enough */ + case SSL_TYPE_ANY: // Any kind of SSL is ok if (vio_type(vio) == VIO_TYPE_SSL) - thd->master_access= acl_user->access; + user_access= acl_user->access; break; case SSL_TYPE_X509: /* Client should have any valid certificate. */ /* - Connections with non-valid certificates are dropped already - in sslaccept() anyway, so we do not check validity here. - - We need to check for absence of SSL because without SSL - we should reject connection. + Connections with non-valid certificates are dropped already + in sslaccept() anyway, so we do not check validity here. + + We need to check for absence of SSL because without SSL + 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_)) - thd->master_access= acl_user->access; + 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 */ /* - We do not check for absence of SSL because without SSL it does - not pass all checks here anyway. - If cipher name is specified, we compare it to actual cipher in - use. + We do not check for absence of SSL because without SSL it does + not pass all checks here anyway. + If cipher name is specified, we compare it to actual cipher in + 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_))) - thd->master_access= acl_user->access; + 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)); 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) @@ -701,11 +704,11 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, { if (global_system_variables.log_warnings) sql_print_error("X509 issuer mismatch: should be '%s' " - "but is '%s'", acl_user->x509_issuer, ptr); + "but is '%s'", acl_user->x509_issuer, ptr); free(ptr); break; } - thd->master_access= acl_user->access; + user_access= acl_user->access; free(ptr); } DBUG_PRINT("info",("checkpoint 4")); @@ -722,7 +725,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, acl_user->x509_subject, ptr); } else - thd->master_access= acl_user->access; + user_access= acl_user->access; free(ptr); } break; @@ -735,6 +738,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, break; #endif /* HAVE_OPENSSL */ } + thd->master_access= user_access; thd->priv_user= acl_user->user ? thd->user : (char *) ""; *mqh= acl_user->user_resource; @@ -1686,6 +1690,7 @@ class GRANT_TABLE :public Sql_alloc public: char *host,*db,*user,*tname, *hash_key; ulong privs, cols; + ulong sort; uint key_length; HASH hash_columns; GRANT_TABLE (const char *h, const char *d,const char *u, const char *t, @@ -1695,6 +1700,7 @@ public: host = strdup_root(&memex,h); db = strdup_root(&memex,d); user = strdup_root(&memex,u); + sort= get_sort(3,host,db,user); tname= strdup_root(&memex,t); if (lower_case_table_names) { @@ -1717,7 +1723,8 @@ public: user = get_field(&memex,form->field[2]); if (!user) user=(char*) ""; - tname = get_field(&memex,form->field[3]); + sort= get_sort(3,host,db,user); + tname= get_field(&memex,form->field[3]); if (!host || !db || !tname) { /* Wrong table row; Ignore it */ @@ -1826,10 +1833,11 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip, } else { - if ((host && !wild_case_compare(&my_charset_latin1, - host,grant_table->host)) || - (ip && !wild_case_compare(&my_charset_latin1, - ip,grant_table->host))) + if (((host && !wild_case_compare(&my_charset_latin1, + host,grant_table->host)) || + (ip && !wild_case_compare(&my_charset_latin1, + ip,grant_table->host))) && + (!found || found->sort < grant_table->sort)) found=grant_table; // Host ok } } @@ -3086,7 +3094,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) protocol->store(global.ptr(),global.length(),global.charset()); if (protocol->write()) { - error=-1; + error= -1; goto end; } } @@ -3144,7 +3152,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) protocol->store(db.ptr(),db.length(),db.charset()); if (protocol->write()) { - error=-1; + error= -1; goto end; } } @@ -3170,15 +3178,19 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if ((table_access | grant_table->cols) != 0) { String global(buff,sizeof(buff),&my_charset_latin1); + ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL; + global.length(0); global.append("GRANT ",6); if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL))) global.append("ALL PRIVILEGES",14); + else if (!test_access) + global.append("USAGE",5); else { int found= 0; - ulong j,test_access= (table_access | grant_table->cols) & ~GRANT_ACL; + ulong j; for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1) { @@ -3345,7 +3357,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) } ACL_USER *check_acl_user(LEX_USER *user_name, - uint *acl_user_idx) + uint *acl_acl_userdx) { ACL_USER *acl_user= 0; uint counter; @@ -3365,14 +3377,14 @@ ACL_USER *check_acl_user(LEX_USER *user_name, if (counter == acl_users.elements) return 0; - *acl_user_idx= counter; + *acl_acl_userdx= counter; return acl_user; } int mysql_drop_user(THD *thd, List <LEX_USER> &list) { - uint counter, user_id; + uint counter, acl_userd; int result; ACL_USER *acl_user; ACL_DB *acl_db; @@ -3392,7 +3404,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list) { if (!(acl_user= check_acl_user(user_name, &counter))) { - sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; No such user", user_name->user.str, user_name->host.str); result= -1; @@ -3400,13 +3412,13 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list) } if ((acl_user->access & ~0)) { - sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Global privileges exists", user_name->user.str, user_name->host.str); result= -1; continue; } - user_id= counter; + acl_userd= counter; for (counter= 0 ; counter < acl_dbs.elements ; counter++) { @@ -3423,7 +3435,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list) } if (counter != acl_dbs.elements) { - sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Database privileges exists", user_name->user.str, user_name->host.str); result= -1; @@ -3446,7 +3458,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list) } if (counter != column_priv_hash.records) { - sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Table privileges exists", user_name->user.str, user_name->host.str); result= -1; @@ -3472,7 +3484,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list) tables[0].table->file->index_end(); DBUG_RETURN(-1); } - delete_dynamic_element(&acl_users, user_id); + delete_dynamic_element(&acl_users, acl_userd); } tables[0].table->file->index_end(); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ba1952e533e..e549b875bcb 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 a49162bb4ef..e8c09b326a5 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 @@ -561,7 +561,6 @@ public: /* scramble - random string sent to client on handshake */ char 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; @@ -581,7 +580,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 { @@ -966,7 +964,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 6cc5d25c34e..6028e291edd 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1452,6 +1452,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); @@ -1472,7 +1474,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 dd6bdf45e82..771b1ab11d6 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -170,7 +170,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 @@ -325,7 +324,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); } } @@ -359,7 +358,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); } } @@ -822,9 +821,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 fc533f9619b..9e7532c447d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -623,7 +623,6 @@ check_connection(THD *thd) thd->ip= 0; bzero((char*) &thd->remote, sizeof(struct sockaddr)); } - /* Ensure that wrong hostnames doesn't cause buffer overflows */ vio_keepalive(net->vio, TRUE); ulong pkt_len= 0; @@ -1828,6 +1827,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; @@ -1881,8 +1881,6 @@ mysql_execute_command(THD *thd) res = mysql_preload_keys(thd, tables); break; } - - #ifdef HAVE_REPLICATION case SQLCOM_CHANGE_MASTER: { @@ -1921,7 +1919,6 @@ mysql_execute_command(THD *thd) res = load_master_data(thd); break; #endif /* HAVE_REPLICATION */ - #ifdef HAVE_INNOBASE_DB case SQLCOM_SHOW_INNODB_STATUS: { @@ -1931,7 +1928,6 @@ mysql_execute_command(THD *thd) break; } #endif - #ifdef HAVE_REPLICATION case SQLCOM_LOAD_MASTER_TABLE: { @@ -2630,11 +2626,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 @@ -3156,7 +3153,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); @@ -3168,7 +3174,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 229fa770b0e..2489bc8df68 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)) @@ -988,7 +988,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)) @@ -1277,7 +1277,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 12d39bfacb0..ccc6e10dee8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -158,7 +158,7 @@ static void copy_sum_funcs(Item_sum **func_ptr); static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab); static bool init_sum_functions(Item_sum **func, Item_sum **end); static bool update_sum_func(Item_sum **func); -static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, +static void select_describe(JOIN *join, bool need_tmp_table,bool need_order, bool distinct, const char *message=NullS); static Item *remove_additional_cond(Item* conds); @@ -2055,28 +2055,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; } @@ -2087,12 +2093,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 @@ -2101,26 +2101,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)++; @@ -2169,12 +2181,14 @@ 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, +#endif + usable_tables); break; case Item_func::OPTIMIZE_OP: { @@ -2188,7 +2202,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 && @@ -2198,7 +2212,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; } @@ -2207,11 +2221,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; } @@ -3330,13 +3347,30 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->best_positions[i].records_read && !(join->select_options & OPTION_FOUND_ROWS))) { + /* Join with outer join condition */ + COND *orig_cond=sel->cond; + sel->cond=and_conds(sel->cond,tab->on_expr); if (sel->test_quick_select(tab->keys, used_tables & ~ current_map, (join->select_options & OPTION_FOUND_ROWS ? HA_POS_ERROR : join->unit->select_limit_cnt)) < 0) - DBUG_RETURN(1); // Impossible range + { /* before reporting "Impossible WHERE" for the whole query + we have to check isn't it only "impossible ON" instead */ + sel->cond=orig_cond; + if (!tab->on_expr || + sel->test_quick_select(tab->keys, + used_tables & ~ current_map, + (join->select_options & + OPTION_FOUND_ROWS ? + HA_POS_ERROR : + join->thd->select_limit)) < 0) + DBUG_RETURN(1); // Impossible WHERE + } + else + sel->cond=orig_cond; + /* Fix for EXPLAIN */ if (sel->quick) join->best_positions[i].records_read= sel->quick->records; @@ -4034,7 +4068,7 @@ static Item *remove_additional_cond(Item* conds) } 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) @@ -4060,7 +4094,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 || @@ -4078,7 +4112,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]); } @@ -4087,7 +4121,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]); } @@ -8248,7 +8282,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 7dd2004b664..685d00db391 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -797,9 +797,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); @@ -1023,11 +1028,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->variables.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 | @@ -1043,9 +1075,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 @@ -1053,13 +1082,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(' '); @@ -1096,9 +1126,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) { @@ -1128,9 +1158,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++) { @@ -1181,7 +1213,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++ = ')'; @@ -1195,10 +1226,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); @@ -1209,8 +1238,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) && @@ -1228,21 +1255,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) @@ -1266,12 +1294,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); } @@ -1528,7 +1559,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; @@ -1542,8 +1574,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, @@ -1631,83 +1662,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: @@ -1717,7 +1748,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"; @@ -1745,40 +1776,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); @@ -1802,14 +1843,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 571ee371721..5f16377d20a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -920,7 +920,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, thd->proc_info="creating table"; + if (thd->variables.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)) { @@ -2585,7 +2588,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, DBUG_RETURN(error > 0 ? -1 : 0); } -int mysql_checksum_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *check_opt) + +int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) { TABLE_LIST *table; List<Item> field_list; @@ -2600,24 +2604,23 @@ int mysql_checksum_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *check_opt) if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); - for (table = tables; table; table = table->next) + for (table= tables; table; table= table->next) { char table_name[NAME_LEN*2+2]; - char* db = (table->db) ? table->db : thd->db; - bool fatal_error=0; + bool fatal_error= 0; TABLE *t; - strxmov(table_name,db ? db : "",".",table->real_name,NullS); - t=table->table = open_ltable(thd, table, TL_READ_NO_INSERT); -#ifdef EMBEDDED_LIBRARY - thd->net.last_errno= 0; // these errors shouldn't get client -#endif + strxmov(table_name, table->db ,".", table->real_name, NullS); + + t= table->table= open_ltable(thd, table, TL_READ_NO_INSERT); + thd->clear_error(); // these errors shouldn't get client protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); if (!t) { + /* Table didn't exist */ protocol->store_null(); thd->net.last_error[0]=0; } @@ -2629,45 +2632,42 @@ int mysql_checksum_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *check_opt) !(check_opt->flags & T_EXTEND)) protocol->store((ulonglong)t->file->checksum()); else if (!(t->file->table_flags() & HA_HAS_CHECKSUM) && - check_opt->flags & T_QUICK) + (check_opt->flags & T_QUICK)) protocol->store_null(); else { /* calculating table's checksum */ - ha_checksum crc=0; + ha_checksum crc= 0; if (t->file->rnd_init(1)) protocol->store_null(); else { while (!t->file->rnd_next(t->record[0])) { - ha_checksum row_crc=0; + ha_checksum row_crc= 0; if (t->record[0] != t->field[0]->ptr) - row_crc=my_checksum(row_crc, t->record[0], - t->field[0]->ptr - t->record[0]); + row_crc= my_checksum(row_crc, t->record[0], + t->field[0]->ptr - t->record[0]); - for (uint i=0; i < t->fields; i++ ) + for (uint i= 0; i < t->fields; i++ ) { - Field *f=t->field[i]; + Field *f= t->field[i]; if (f->type() == FIELD_TYPE_BLOB) { String tmp; f->val_str(&tmp,&tmp); - row_crc=my_checksum(row_crc, tmp.ptr(), tmp.length()); + row_crc= my_checksum(row_crc, tmp.ptr(), tmp.length()); } else - row_crc=my_checksum(row_crc, f->ptr, f->pack_length()); + row_crc= my_checksum(row_crc, f->ptr, f->pack_length()); } - crc+=row_crc; + crc+= row_crc; } protocol->store((ulonglong)crc); } } -#ifdef EMBEDDED_LIBRARY - thd->net.last_errno= 0; // these errors shouldn't get client -#endif - + thd->clear_error(); close_thread_tables(thd); table->table=0; // For query cache } @@ -2677,6 +2677,7 @@ int mysql_checksum_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *check_opt) send_eof(thd); DBUG_RETURN(0); + err: close_thread_tables(thd); // Shouldn't be needed if (table) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 55f697e9981..381311b4975 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)) @@ -267,6 +266,11 @@ int st_select_lex_unit::exec() 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 @@ -278,10 +282,10 @@ int st_select_lex_unit::exec() sl->options|= found_rows_for_union; } - /* - As far as union share table space we should reassign table map, - which can be spoiled by 'prepare' of JOIN of other UNION parts - if it use same tables + /* + As far as union share table space we should reassign table map, + which can be spoiled by 'prepare' of JOIN of other UNION parts + if it use same tables */ uint tablenr=0; for (TABLE_LIST *table_list= (TABLE_LIST*) sl->table_list.first; @@ -318,11 +322,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 +347,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 */ |