diff --git a/sql/item_func.cc b/sql/item_func.cc index 7e8213b4380fc5da344df931a05d30f3696480b5..b861ccdb46375174e79bc4dbc8cc1495eec1cdd9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -743,17 +743,31 @@ double Item_func_round::val() double Item_func_rand::val() { + THD* thd = current_thd; if (arg_count) { // Only use argument once in query uint32 tmp= (uint32) (args[0]->val_int()); - randominit(¤t_thd->rand,(uint32) (tmp*0x10001L+55555555L), + randominit(&thd->rand,(uint32) (tmp*0x10001L+55555555L), (uint32) (tmp*0x10000001L)); #ifdef DELETE_ITEMS delete args[0]; #endif arg_count=0; } - return rnd(¤t_thd->rand); + else if (!thd->rand_used) + { + // no need to send a Rand log event if seed was given eg: RAND(seed), + // as it will be replicated in the query as such. + + // save the seed only the first time RAND() is used in the query + + // once events are forwarded rather than recreated, + // the following can be skipped if inside the slave thread + thd->rand_used=1; + thd->rand_saved_seed1=thd->rand.seed1; + thd->rand_saved_seed2=thd->rand.seed2; + } + return rnd(&thd->rand); } longlong Item_func_sign::val_int() diff --git a/sql/log.cc b/sql/log.cc index 91ef42e1381b51354ecbb2e43636b97d256ba53f..fd5f6d0d73f283f7559b29746d972071c17f94b1 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1072,6 +1072,13 @@ bool MYSQL_LOG::write(Log_event* event_info) if (e.write(file)) goto err; } + if (thd && thd->rand_used) + { + Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2); + e.set_log_pos(this); + if (e.write(file)) + goto err; + } if (thd && thd->variables.convert_set) { char buf[1024] = "SET CHARACTER SET "; diff --git a/sql/log_event.cc b/sql/log_event.cc index 1e6fe92468237472dac175b07e6fcdeed8e4b788..79c7fd8e99c37ed6378a20cb30b3d7706aabbfd8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -348,6 +348,18 @@ void Intvar_log_event::pack_info(String* packet) net_store_data(packet, tmp.ptr(), tmp.length()); } +void Rand_log_event::pack_info(String* packet) +{ + char buf1[256], buf[22]; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append("randseed1="); + tmp.append(llstr(seed1, buf)); + tmp.append(",randseed2="); + tmp.append(llstr(seed2, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} + void Slave_log_event::pack_info(String* packet) { char buf1[256], buf[22], *end; @@ -376,6 +388,9 @@ void Log_event::init_show_field_list(List<Item>* field_list) field_list->push_back(new Item_empty_string("Info", 20)); } +/* + * only called by SHOW BINLOG EVENTS + */ int Log_event::net_send(THD* thd, const char* log_name, my_off_t pos) { String* packet = &thd->packet; @@ -610,6 +625,9 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, case INTVAR_EVENT: ev = new Intvar_log_event(buf, old_format); break; + case RAND_EVENT: + ev = new Rand_log_event(buf, old_format); + break; default: break; } @@ -915,6 +933,41 @@ void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) } #endif +/***************************************************************************** + * + * Rand log event + * + ****************************************************************************/ +Rand_log_event::Rand_log_event(const char* buf, bool old_format) + :Log_event(buf, old_format) +{ + buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + seed1 = uint8korr(buf+RAND_SEED1_OFFSET); + seed2 = uint8korr(buf+RAND_SEED2_OFFSET); +} + +int Rand_log_event::write_data(IO_CACHE* file) +{ + char buf[16]; + int8store(buf + RAND_SEED1_OFFSET, seed1); + int8store(buf + RAND_SEED2_OFFSET, seed2); + return my_b_safe_write(file, (byte*) buf, sizeof(buf)); +} + +#ifdef MYSQL_CLIENT +void Rand_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char llbuff[22]; + if (!short_form) + { + print_header(file); + fprintf(file, "\tRand\n"); + } + fprintf(file, "SET RAND SEED1=%s;\n", llstr(seed1, llbuff)); + fprintf(file, "SET RAND SEED2=%s;\n", llstr(seed2, llbuff)); + fflush(file); +} +#endif int Load_log_event::write_data_header(IO_CACHE* file) { @@ -1926,6 +1979,14 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli) return 0; } +int Rand_log_event::exec_event(struct st_relay_log_info* rli) +{ + thd->rand.seed1 = seed1; + thd->rand.seed2 = seed2; + rli->inc_pending(get_event_len()); + return 0; +} + int Slave_log_event::exec_event(struct st_relay_log_info* rli) { if (mysql_bin_log.is_open()) diff --git a/sql/log_event.h b/sql/log_event.h index 5f7aa4ad586ba6aebbe3b93aab98a7ab3b4ae754..ad0a44f9b4afa43e40c6b8528007daf5a2ec294a 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -152,6 +152,11 @@ struct sql_ex_info #define I_TYPE_OFFSET 0 #define I_VAL_OFFSET 1 +/* Rand event post-header */ + +#define RAND_SEED1_OFFSET 0 +#define RAND_SEED2_OFFSET 8 + /* Load event post-header */ #define L_THREAD_ID_OFFSET 0 @@ -199,7 +204,7 @@ enum Log_event_type START_EVENT = 1, QUERY_EVENT =2, STOP_EVENT=3, ROTATE_EVENT = 4, INTVAR_EVENT=5, LOAD_EVENT=6, SLAVE_EVENT=7, CREATE_FILE_EVENT=8, APPEND_BLOCK_EVENT=9, EXEC_LOAD_EVENT=10, DELETE_FILE_EVENT=11, - NEW_LOAD_EVENT=12 + NEW_LOAD_EVENT=12, RAND_EVENT=13 }; enum Int_event_type @@ -497,6 +502,34 @@ class Intvar_log_event: public Log_event bool is_valid() { return 1; } }; +/***************************************************************************** + * + * Rand log event class + * + ****************************************************************************/ +class Rand_log_event: public Log_event +{ + public: + ulonglong seed1; + ulonglong seed2; + +#ifndef MYSQL_CLIENT + Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg) + :Log_event(thd_arg),seed1(seed1_arg),seed2(seed2_arg) + {} + void pack_info(String* packet); + int exec_event(struct st_relay_log_info* rli); +#else + void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif + + Rand_log_event(const char* buf, bool old_format); + ~Rand_log_event() {} + Log_event_type get_type_code() { return RAND_EVENT;} + int get_data_size() { return sizeof(ulonglong) * 2; } + int write_data(IO_CACHE* file); + bool is_valid() { return 1; } +}; class Stop_log_event: public Log_event { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e9ea61f4f1fcb02f4799f119109719d3ccb90ce1..dab8d153c829d0584d9ba7d2e7d28838462839e6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -81,7 +81,7 @@ static void free_var(user_var_entry *entry) THD::THD():user_time(0), fatal_error(0), last_insert_id_used(0), - insert_id_used(0), in_lock_tables(0), + insert_id_used(0), rand_used(0), in_lock_tables(0), global_read_lock(0), bootstrap(0) { host=user=priv_user=db=query=ip=0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 7b5a6da8c6b44d8e3c105aa2e76afe949cbda974..09946822dca90d007f32d869d86dbf894616480d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -501,7 +501,8 @@ class THD :public ilink { bool set_query_id,locked,count_cuted_fields,some_tables_deleted; bool no_errors, allow_sum_func, password; bool fatal_error; - bool query_start_used,last_insert_id_used,insert_id_used; + bool query_start_used,last_insert_id_used,insert_id_used,rand_used; + ulonglong rand_saved_seed1, rand_saved_seed2; bool system_thread,in_lock_tables,global_read_lock; bool query_error, bootstrap, cleanup_done; bool safe_to_cache_query; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 046b5d45b59c3723edbd9782fd67445eb4f6e933..ae32cd078f75c79731a76b4a2d2a8d7a84975d16 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2912,6 +2912,7 @@ mysql_init_query(THD *thd) thd->total_warn_count=0; // Warnings for this query thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; thd->sent_row_count= thd->examined_row_count= 0; + thd->rand_used=0; thd->safe_to_cache_query= 1; thd->lex.param_list.empty(); DBUG_VOID_RETURN;