From 60bdb90f999e8ac643d83e6d9b7b23fe5b150b57 Mon Sep 17 00:00:00 2001 From: "nick@mysql.com" <> Date: Tue, 29 Oct 2002 17:33:03 -0700 Subject: [PATCH 1/8] Delete: mysql-test/std_data/master-bin.001 --- mysql-test/std_data/master-bin.001 | Bin 98 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mysql-test/std_data/master-bin.001 diff --git a/mysql-test/std_data/master-bin.001 b/mysql-test/std_data/master-bin.001 deleted file mode 100644 index 2ec2397acdda61bd2efa25959f63e98b9a18d16c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98 zcmeyDl$obJN#B~0iGhK^8;BW!n1O+b!9>qM&p-%pjwL G;c5Z2Hwv@> From cb1d72e44d1b636041dd58f0e03b8eecf638ffb4 Mon Sep 17 00:00:00 2001 From: "nick@mysql.com" <> Date: Tue, 29 Oct 2002 17:34:17 -0700 Subject: [PATCH 2/8] set my checkout behavior to bk -r get --- BitKeeper/etc/config | 1 + 1 file changed, 1 insertion(+) diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config index 85b5a871301..8305314e51b 100644 --- a/BitKeeper/etc/config +++ b/BitKeeper/etc/config @@ -69,4 +69,5 @@ pager: hours: [serg:]checkout:get [arjen:]checkout:get +[nick:]checkout:get checkout:edit From 6d88799e9595d43fd051831b1c746c505563938c Mon Sep 17 00:00:00 2001 From: "nick@mysql.com" <> Date: Tue, 29 Oct 2002 23:50:07 -0700 Subject: [PATCH 3/8] Reordered functions--grouped by class now. Added comment blocks. --- .bzrignore | 2 + sql/log_event.cc | 2995 ++++++++++++++++++++++++++++------------------ sql/log_event.h | 107 +- 3 files changed, 1905 insertions(+), 1199 deletions(-) diff --git a/.bzrignore b/.bzrignore index bacfe2ff975..0a6384dfccb 100644 --- a/.bzrignore +++ b/.bzrignore @@ -513,3 +513,5 @@ innobase/stamp-h1 myisam/rt_test.MYD myisam/rt_test.MYI stamp-h1 +scripts/fill_func_tables +scripts/fill_func_tables.sql diff --git a/sql/log_event.cc b/sql/log_event.cc index 50cfb835a5c..014cdcb4961 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -26,6 +26,11 @@ #include +/***************************************************************************** + + my_b_safe_write() + + ****************************************************************************/ inline int my_b_safe_write(IO_CACHE* file, const byte *buf, int len) { @@ -40,6 +45,11 @@ inline int my_b_safe_write(IO_CACHE* file, const byte *buf, return my_b_write(file, buf,len); } +/***************************************************************************** + + pretty_print_str() + + ****************************************************************************/ #ifdef MYSQL_CLIENT static void pretty_print_str(FILE* file, char* str, int len) { @@ -63,16 +73,26 @@ static void pretty_print_str(FILE* file, char* str, int len) } fputc('\'', file); } -#endif +#endif // MYSQL_CLIENT +/***************************************************************************** + + ignored_error_code() + + ****************************************************************************/ #ifndef MYSQL_CLIENT - inline int ignored_error_code(int err_code) { return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code); } +#endif // !MYSQL_CLIENT +/***************************************************************************** + pretty_print_str() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT static void pretty_print_str(String* packet, char* str, int len) { char* end = str + len; @@ -95,8 +115,14 @@ static void pretty_print_str(String* packet, char* str, int len) } packet->append('\''); } +#endif // !MYSQL_CLIENT +/***************************************************************************** + slave_load_file_stem() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT static inline char* slave_load_file_stem(char*buf, uint file_id, int event_server_id) { @@ -108,9 +134,81 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, *buf++ = '-'; return int10_to_str(file_id, buf, 10); } +#endif // !MYSQL_CLIENT -#endif +/***************************************************************************** + cleanup_load_tmpdir() + + Delete all temporary files used for SQL_LOAD. + + TODO + - When we get a 'server start' event, we should only remove + the files associated with the server id that just started. + Easily fixable by adding server_id as a prefix to the log files. + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +static void cleanup_load_tmpdir() +{ + MY_DIR *dirp; + FILEINFO *file; + uint i; + if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) + return; + + for (i=0 ; i < (uint)dirp->number_off_files; i++) + { + file=dirp->dir_entry+i; + if (is_prefix(file->name,"SQL_LOAD-")) + my_delete(file->name, MYF(0)); + } + + my_dirend(dirp); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + write_str() + + ****************************************************************************/ +static bool write_str(IO_CACHE *file, char *str, byte length) +{ + return (my_b_safe_write(file, &length, 1) || + my_b_safe_write(file, (byte*) str, (int) length)); +} + +/***************************************************************************** + + read_str() + + ****************************************************************************/ +static inline int read_str(char * &buf, char *buf_end, char * &str, + uint8 &len) +{ + if (buf + (uint) (uchar) *buf >= buf_end) + return 1; + len = (uint8) *buf; + str= buf+1; + buf+= (uint) len+1; + return 0; +} + + +/***************************************************************************** + ***************************************************************************** + + Log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Log_event::get_type_str() + + ****************************************************************************/ const char* Log_event::get_type_str() { switch(get_type_code()) { @@ -131,6 +229,11 @@ const char* Log_event::get_type_str() } } +/***************************************************************************** + + Log_event::Log_event() + + ****************************************************************************/ #ifndef MYSQL_CLIENT Log_event::Log_event(THD* thd_arg, uint16 flags_arg) :exec_time(0), flags(flags_arg), cached_event_len(0), @@ -139,46 +242,23 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg) if (thd) { server_id = thd->server_id; - when = thd->start_time; - log_pos = thd->log_pos; + when = thd->start_time; + log_pos = thd->log_pos; } else { server_id = ::server_id; - when = time(NULL); - log_pos=0; + when = time(NULL); + log_pos =0; } } +#endif // !MYSQL_CLIENT -/* - Delete all temporary files used for SQL_LOAD. +/***************************************************************************** - TODO - - When we get a 'server start' event, we should only remove - the files associated with the server id that just started. - Easily fixable by adding server_id as a prefix to the log files. -*/ - -static void cleanup_load_tmpdir() -{ - MY_DIR *dirp; - FILEINFO *file; - uint i; - if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) - return; - - for (i=0 ; i < (uint)dirp->number_off_files; i++) - { - file=dirp->dir_entry+i; - if (is_prefix(file->name,"SQL_LOAD-")) - my_delete(file->name, MYF(0)); - } - - my_dirend(dirp); -} - -#endif + Log_event::Log_event() + ****************************************************************************/ Log_event::Log_event(const char* buf, bool old_format) :cached_event_len(0), temp_buf(0) { @@ -202,6 +282,11 @@ Log_event::Log_event(const char* buf, bool old_format) #ifndef MYSQL_CLIENT +/***************************************************************************** + + Log_event::exec_event() + + ****************************************************************************/ int Log_event::exec_event(struct st_relay_log_info* rli) { if (rli) // QQ When is this not true ? @@ -213,172 +298,21 @@ int Log_event::exec_event(struct st_relay_log_info* rli) return 0; } +/***************************************************************************** + + Log_event::pack_info() + + ****************************************************************************/ void Log_event::pack_info(String* packet) { net_store_data(packet, "", 0); } -void Query_log_event::pack_info(String* packet) -{ - char buf[256]; - String tmp(buf, sizeof(buf), system_charset_info); - tmp.length(0); - if (db && db_len) - { - tmp.append("use `", 5); - tmp.append(db, db_len); - tmp.append("`; ", 3); - } - - if (query && q_len) - tmp.append(query, q_len); - net_store_data(packet, (char*)tmp.ptr(), tmp.length()); -} - -void Start_log_event::pack_info(String* packet) -{ - char buf1[256]; - String tmp(buf1, sizeof(buf1), system_charset_info); - tmp.length(0); - char buf[22]; - - tmp.append("Server ver: "); - tmp.append(server_version); - tmp.append(", Binlog ver: "); - tmp.append(llstr(binlog_version, buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); -} - -void Load_log_event::pack_info(String* packet) -{ - char buf[256]; - String tmp(buf, sizeof(buf), system_charset_info); - tmp.length(0); - if (db && db_len) - { - tmp.append("use "); - tmp.append(db, db_len); - tmp.append("; ", 2); - } - - tmp.append("LOAD DATA INFILE '"); - tmp.append(fname, fname_len); - tmp.append("' ", 2); - if (sql_ex.opt_flags && REPLACE_FLAG ) - tmp.append(" REPLACE "); - else if (sql_ex.opt_flags && IGNORE_FLAG ) - tmp.append(" IGNORE "); - - tmp.append("INTO TABLE "); - tmp.append(table_name); - if (sql_ex.field_term_len) - { - tmp.append(" FIELDS TERMINATED BY "); - pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len); - } - - if (sql_ex.enclosed_len) - { - if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) - tmp.append(" OPTIONALLY "); - tmp.append( " ENCLOSED BY "); - pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len); - } - - if (sql_ex.escaped_len) - { - tmp.append( " ESCAPED BY "); - pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); - } - - if (sql_ex.line_term_len) - { - tmp.append(" LINES TERMINATED BY "); - pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); - } - - if (sql_ex.line_start_len) - { - tmp.append(" LINES STARTING BY "); - pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); - } - - if ((int)skip_lines > 0) - tmp.append( " IGNORE %ld LINES ", (long) skip_lines); - - if (num_fields) - { - uint i; - const char* field = fields; - tmp.append(" ("); - for (i = 0; i < num_fields; i++) - { - if (i) - tmp.append(" ,"); - tmp.append( field); - - field += field_lens[i] + 1; - } - tmp.append(')'); - } - - net_store_data(packet, tmp.ptr(), tmp.length()); -} - -void Rotate_log_event::pack_info(String* packet) -{ - char buf1[256], buf[22]; - String tmp(buf1, sizeof(buf1), system_charset_info); - tmp.length(0); - tmp.append(new_log_ident, ident_len); - tmp.append(";pos="); - tmp.append(llstr(pos,buf)); - if (flags & LOG_EVENT_FORCED_ROTATE_F) - tmp.append("; forced by master"); - net_store_data(packet, tmp.ptr(), tmp.length()); -} - -void Intvar_log_event::pack_info(String* packet) -{ - char buf1[256], buf[22]; - String tmp(buf1, sizeof(buf1), system_charset_info); - tmp.length(0); - tmp.append(get_var_type_name()); - tmp.append('='); - tmp.append(llstr(val, buf)); - 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; - String tmp(buf1, sizeof(buf1), system_charset_info); - tmp.length(0); - tmp.append("host="); - tmp.append(master_host); - tmp.append(",port="); - end= int10_to_str((long) master_port, buf, 10); - tmp.append(buf, (uint32) (end-buf)); - tmp.append(",log="); - tmp.append(master_log); - tmp.append(",pos="); - tmp.append(llstr(master_pos,buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); -} +/***************************************************************************** + Log_event::init_show_field_list() + ****************************************************************************/ void Log_event::init_show_field_list(List* field_list) { field_list->push_back(new Item_empty_string("Log_name", 20)); @@ -389,9 +323,13 @@ void Log_event::init_show_field_list(List* field_list) field_list->push_back(new Item_empty_string("Info", 20)); } -/* - * only called by SHOW BINLOG EVENTS - */ +/***************************************************************************** + + Log_event::net_send() + + 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; @@ -410,22 +348,23 @@ int Log_event::net_send(THD* thd, const char* log_name, my_off_t pos) pack_info(packet); return my_net_write(&thd->net, (char*) packet->ptr(), packet->length()); } +#endif // !MYSQL_CLIENT -#endif /* MYSQL_CLIENT */ - - -int Query_log_event::write(IO_CACHE* file) -{ - return query ? Log_event::write(file) : -1; -} +/***************************************************************************** + Log_event::write() + ****************************************************************************/ int Log_event::write(IO_CACHE* file) { return (write_header(file) || write_data(file)) ? -1 : 0; } +/***************************************************************************** + Log_event::write_header() + + ****************************************************************************/ int Log_event::write_header(IO_CACHE* file) { char buf[LOG_EVENT_HEADER_LEN]; @@ -445,8 +384,13 @@ int Log_event::write_header(IO_CACHE* file) return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf))); } -#ifndef MYSQL_CLIENT +/***************************************************************************** + + Log_event::read_log_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Log_event::read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock) { @@ -501,8 +445,7 @@ end: pthread_mutex_unlock(log_lock); DBUG_RETURN(result); } - -#endif // MYSQL_CLIENT +#endif // !MYSQL_CLIENT #ifndef MYSQL_CLIENT #define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock); @@ -513,7 +456,13 @@ end: #define LOCK_MUTEX #endif -// allocates memory - the caller is responsible for clean-up +/***************************************************************************** + + Log_event::read_log_event() + + Allocates memory--the caller is responsible for clean-up + + ****************************************************************************/ #ifndef MYSQL_CLIENT Log_event* Log_event::read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock, @@ -576,7 +525,11 @@ data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]); return res; } +/***************************************************************************** + Log_event::read_log_event() + + ****************************************************************************/ Log_event* Log_event::read_log_event(const char* buf, int event_len, const char **error, bool old_format) { @@ -642,8 +595,13 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, return ev; } - #ifdef MYSQL_CLIENT + +/***************************************************************************** + + Log_event::print_header() + + ****************************************************************************/ void Log_event::print_header(FILE* file) { char llbuff[22]; @@ -653,6 +611,11 @@ void Log_event::print_header(FILE* file) llstr(log_pos,llbuff)); } +/***************************************************************************** + + Log_event::print_timestamp() + + ****************************************************************************/ void Log_event::print_timestamp(FILE* file, time_t* ts) { struct tm *res; @@ -674,113 +637,91 @@ void Log_event::print_timestamp(FILE* file, time_t* ts) res->tm_sec); } +#endif // MYSQL_CLIENT -void Start_log_event::print(FILE* file, bool short_form, char* last_db) +/***************************************************************************** + + Log_event::set_log_pos() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Log_event::set_log_pos(MYSQL_LOG* log) { - if (short_form) - return; - - print_header(file); - fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, - server_version); - print_timestamp(file, (time_t*)&created); - fputc('\n', file); - fflush(file); + if (!log_pos) + log_pos = my_b_tell(&log->log_file); } +#endif // !MYSQL_CLIENT -void Stop_log_event::print(FILE* file, bool short_form, char* last_db) + + +/***************************************************************************** + ***************************************************************************** + + Query_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +#ifndef MYSQL_CLIENT +/***************************************************************************** + + Query_log_event::pack_info() + + ****************************************************************************/ +void Query_log_event::pack_info(String* packet) { - if (short_form) - return; - - print_header(file); - fprintf(file, "\tStop\n"); - fflush(file); -} - -void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) -{ - char buf[22]; - if (short_form) - return; - - print_header(file); - fprintf(file, "\tRotate to "); - if (new_log_ident) - my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, - MYF(MY_NABP | MY_WME)); - fprintf(file, " pos: %s", llstr(pos, buf)); - if (flags & LOG_EVENT_FORCED_ROTATE_F) - fprintf(file," forced by master"); - fputc('\n', file); - fflush(file); -} - -#endif /* #ifdef MYSQL_CLIENT */ - - -Start_log_event::Start_log_event(const char* buf, - bool old_format) - :Log_event(buf, old_format) -{ - buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; - binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET); - memcpy(server_version, buf+ST_SERVER_VER_OFFSET, - ST_SERVER_VER_LEN); - created = uint4korr(buf+ST_CREATED_OFFSET); -} - -int Start_log_event::write_data(IO_CACHE* file) -{ - char buff[START_HEADER_LEN]; - int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version); - memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN); - int4store(buff + ST_CREATED_OFFSET,created); - return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); -} - - -Rotate_log_event::Rotate_log_event(const char* buf, int event_len, - bool old_format) - :Log_event(buf, old_format),new_log_ident(NULL),alloced(0) -{ - // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET - int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; - uint ident_offset; - if (event_len < header_size) - return; - buf += header_size; - if (old_format) + char buf[256]; + String tmp(buf, sizeof(buf), system_charset_info); + tmp.length(0); + if (db && db_len) { - ident_len = (uint)(event_len - OLD_HEADER_LEN); - pos = 4; - ident_offset = 0; + tmp.append("use `", 5); + tmp.append(db, db_len); + tmp.append("`; ", 3); } - else - { - ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD); - pos = uint8korr(buf + R_POS_OFFSET); - ident_offset = ROTATE_HEADER_LEN; - } - set_if_smaller(ident_len,FN_REFLEN-1); - if (!(new_log_ident= my_strdup_with_length((byte*) buf + - ident_offset, - (uint) ident_len, - MYF(MY_WME)))) - return; - alloced = 1; + + if (query && q_len) + tmp.append(query, q_len); + net_store_data(packet, (char*)tmp.ptr(), tmp.length()); } +#endif // !MYSQL_CLIENT +/***************************************************************************** -int Rotate_log_event::write_data(IO_CACHE* file) + Query_log_event::write() + + ****************************************************************************/ +int Query_log_event::write(IO_CACHE* file) { - char buf[ROTATE_HEADER_LEN]; - int8store(buf, pos + R_POS_OFFSET); - return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) || - my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); + return query ? Log_event::write(file) : -1; } +/***************************************************************************** + Query_log_event::write_data() + + ****************************************************************************/ +int Query_log_event::write_data(IO_CACHE* file) +{ + if (!query) + return -1; + + char buf[QUERY_HEADER_LEN]; + int4store(buf + Q_THREAD_ID_OFFSET, thread_id); + int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); + buf[Q_DB_LEN_OFFSET] = (char) db_len; + int2store(buf + Q_ERR_CODE_OFFSET, error_code); + + return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) || + my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) || + my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0; +} + +/***************************************************************************** + + Query_log_event::Query_log_event() + + ****************************************************************************/ #ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans) @@ -796,8 +737,13 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, exec_time = (ulong) (end_time - thd->start_time); db_len = (db) ? (uint32) strlen(db) : 0; } -#endif +#endif // MYSQL_CLIENT +/***************************************************************************** + + Query_log_event::Query_log_event() + + ****************************************************************************/ Query_log_event::Query_log_event(const char* buf, int event_len, bool old_format) :Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL) @@ -833,9 +779,12 @@ Query_log_event::Query_log_event(const char* buf, int event_len, *((char*)query+q_len) = 0; } +/***************************************************************************** + Query_log_event::print() + + ****************************************************************************/ #ifdef MYSQL_CLIENT - void Query_log_event::print(FILE* file, bool short_form, char* last_db) { char buff[40],*end; // Enough for SET TIMESTAMP @@ -863,819 +812,13 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fprintf(file, ";\n"); } -#endif - - -int Query_log_event::write_data(IO_CACHE* file) -{ - if (!query) - return -1; - - char buf[QUERY_HEADER_LEN]; - int4store(buf + Q_THREAD_ID_OFFSET, thread_id); - int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); - buf[Q_DB_LEN_OFFSET] = (char) db_len; - int2store(buf + Q_ERR_CODE_OFFSET, error_code); - - return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) || - my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) || - my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0; -} - -Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) - :Log_event(buf, old_format) -{ - buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; - type = buf[I_TYPE_OFFSET]; - val = uint8korr(buf+I_VAL_OFFSET); -} - -const char* Intvar_log_event::get_var_type_name() -{ - switch(type) { - case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID"; - case INSERT_ID_EVENT: return "INSERT_ID"; - default: /* impossible */ return "UNKNOWN"; - } -} - -int Intvar_log_event::write_data(IO_CACHE* file) -{ - char buf[9]; - buf[I_TYPE_OFFSET] = type; - int8store(buf + I_VAL_OFFSET, val); - return my_b_safe_write(file, (byte*) buf, sizeof(buf)); -} - -#ifdef MYSQL_CLIENT -void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) -{ - char llbuff[22]; - const char *msg; - LINT_INIT(msg); - - if (!short_form) - { - print_header(file); - fprintf(file, "\tIntvar\n"); - } - - fprintf(file, "SET "); - switch (type) { - case LAST_INSERT_ID_EVENT: - msg="LAST_INSERT_ID"; - break; - case INSERT_ID_EVENT: - msg="INSERT_ID"; - break; - } - fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); - fflush(file); -} -#endif +#endif // MYSQL_CLIENT /***************************************************************************** - * - * Rand log event - * + + Query_log_event::exec_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) -{ - char buf[LOAD_HEADER_LEN]; - int4store(buf + L_THREAD_ID_OFFSET, thread_id); - int4store(buf + L_EXEC_TIME_OFFSET, exec_time); - int4store(buf + L_SKIP_LINES_OFFSET, skip_lines); - buf[L_TBL_LEN_OFFSET] = (char)table_name_len; - buf[L_DB_LEN_OFFSET] = (char)db_len; - int4store(buf + L_NUM_FIELDS_OFFSET, num_fields); - return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN); -} - -int Load_log_event::write_data_body(IO_CACHE* file) -{ - if (sql_ex.write_data(file)) - return 1; - if (num_fields && fields && field_lens) - { - if (my_b_safe_write(file, (byte*)field_lens, num_fields) || - my_b_safe_write(file, (byte*)fields, field_block_len)) - return 1; - } - return (my_b_safe_write(file, (byte*)table_name, table_name_len + 1) || - my_b_safe_write(file, (byte*)db, db_len + 1) || - my_b_safe_write(file, (byte*)fname, fname_len)); -} - - - -static bool write_str(IO_CACHE *file, char *str, byte length) -{ - return (my_b_safe_write(file, &length, 1) || - my_b_safe_write(file, (byte*) str, (int) length)); -} - - -int sql_ex_info::write_data(IO_CACHE* file) -{ - if (new_format()) - { - return (write_str(file, field_term, field_term_len) || - write_str(file, enclosed, enclosed_len) || - write_str(file, line_term, line_term_len) || - write_str(file, line_start, line_start_len) || - write_str(file, escaped, escaped_len) || - my_b_safe_write(file,(byte*) &opt_flags,1)); - } - else - { - old_sql_ex old_ex; - old_ex.field_term= *field_term; - old_ex.enclosed= *enclosed; - old_ex.line_term= *line_term; - old_ex.line_start= *line_start; - old_ex.escaped= *escaped; - old_ex.opt_flags= opt_flags; - old_ex.empty_flags=empty_flags; - return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex)); - } -} - - -static inline int read_str(char * &buf, char *buf_end, char * &str, - uint8 &len) -{ - if (buf + (uint) (uchar) *buf >= buf_end) - return 1; - len = (uint8) *buf; - str= buf+1; - buf+= (uint) len+1; - return 0; -} - - -char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) -{ - cached_new_format = use_new_format; - if (use_new_format) - { - empty_flags=0; - /* - The code below assumes that buf will not disappear from - under our feet during the lifetime of the event. This assumption - holds true in the slave thread if the log is in new format, but is not - the case when we have old format because we will be reusing net buffer - to read the actual file before we write out the Create_file event. - */ - if (read_str(buf, buf_end, field_term, field_term_len) || - read_str(buf, buf_end, enclosed, enclosed_len) || - read_str(buf, buf_end, line_term, line_term_len) || - read_str(buf, buf_end, line_start, line_start_len) || - read_str(buf, buf_end, escaped, escaped_len)) - return 0; - opt_flags = *buf++; - } - else - { - field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1; - field_term = buf++; // Use first byte in string - enclosed= buf++; - line_term= buf++; - line_start= buf++; - escaped= buf++; - opt_flags = *buf++; - empty_flags= *buf++; - if (empty_flags & FIELD_TERM_EMPTY) - field_term_len=0; - if (empty_flags & ENCLOSED_EMPTY) - enclosed_len=0; - if (empty_flags & LINE_TERM_EMPTY) - line_term_len=0; - if (empty_flags & LINE_START_EMPTY) - line_start_len=0; - if (empty_flags & ESCAPED_EMPTY) - escaped_len=0; - } - return buf; -} - - -#ifndef MYSQL_CLIENT -Load_log_event::Load_log_event(THD* thd, sql_exchange* ex, - const char* db_arg, const char* table_name_arg, - List& fields_arg, - enum enum_duplicates handle_dup) - :Log_event(thd),thread_id(thd->thread_id), num_fields(0),fields(0), - field_lens(0),field_block_len(0), - table_name(table_name_arg ? table_name_arg : ""), - db(db_arg), fname(ex->file_name) -{ - time_t end_time; - time(&end_time); - exec_time = (ulong) (end_time - thd->start_time); - /* db can never be a zero pointer in 4.0 */ - db_len = (uint32) strlen(db); - table_name_len = (uint32) strlen(table_name); - fname_len = (fname) ? (uint) strlen(fname) : 0; - sql_ex.field_term = (char*) ex->field_term->ptr(); - sql_ex.field_term_len = (uint8) ex->field_term->length(); - sql_ex.enclosed = (char*) ex->enclosed->ptr(); - sql_ex.enclosed_len = (uint8) ex->enclosed->length(); - sql_ex.line_term = (char*) ex->line_term->ptr(); - sql_ex.line_term_len = (uint8) ex->line_term->length(); - sql_ex.line_start = (char*) ex->line_start->ptr(); - sql_ex.line_start_len = (uint8) ex->line_start->length(); - sql_ex.escaped = (char*) ex->escaped->ptr(); - sql_ex.escaped_len = (uint8) ex->escaped->length(); - sql_ex.opt_flags = 0; - sql_ex.cached_new_format = -1; - - if (ex->dumpfile) - sql_ex.opt_flags |= DUMPFILE_FLAG; - if (ex->opt_enclosed) - sql_ex.opt_flags |= OPT_ENCLOSED_FLAG; - - sql_ex.empty_flags = 0; - - switch (handle_dup) { - case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break; - case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break; - case DUP_ERROR: break; - } - - if (!ex->field_term->length()) - sql_ex.empty_flags |= FIELD_TERM_EMPTY; - if (!ex->enclosed->length()) - sql_ex.empty_flags |= ENCLOSED_EMPTY; - if (!ex->line_term->length()) - sql_ex.empty_flags |= LINE_TERM_EMPTY; - if (!ex->line_start->length()) - sql_ex.empty_flags |= LINE_START_EMPTY; - if (!ex->escaped->length()) - sql_ex.empty_flags |= ESCAPED_EMPTY; - - skip_lines = ex->skip_lines; - - List_iterator li(fields_arg); - field_lens_buf.length(0); - fields_buf.length(0); - Item* item; - while ((item = li++)) - { - num_fields++; - uchar len = (uchar) strlen(item->name); - field_block_len += len + 1; - fields_buf.append(item->name, len + 1); - field_lens_buf.append((char*)&len, 1); - } - - field_lens = (const uchar*)field_lens_buf.ptr(); - fields = fields_buf.ptr(); -} - -#endif - -/* - The caller must do buf[event_len] = 0 before he starts using the - constructed event. -*/ - -Load_log_event::Load_log_event(const char* buf, int event_len, - bool old_format): - Log_event(buf, old_format),num_fields(0),fields(0), - field_lens(0),field_block_len(0), - table_name(0),db(0),fname(0) -{ - if (!event_len) // derived class, will call copy_log_event() itself - return; - copy_log_event(buf, event_len, old_format); -} - -int Load_log_event::copy_log_event(const char *buf, ulong event_len, - bool old_format) -{ - uint data_len; - char* buf_end = (char*)buf + event_len; - const char* data_head = buf + ((old_format) ? - OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN); - thread_id = uint4korr(data_head + L_THREAD_ID_OFFSET); - exec_time = uint4korr(data_head + L_EXEC_TIME_OFFSET); - skip_lines = uint4korr(data_head + L_SKIP_LINES_OFFSET); - table_name_len = (uint)data_head[L_TBL_LEN_OFFSET]; - db_len = (uint)data_head[L_DB_LEN_OFFSET]; - num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET); - - int body_offset = ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ? - LOAD_HEADER_LEN + OLD_HEADER_LEN : - get_data_body_offset()); - - if ((int) event_len < body_offset) - return 1; - /* - Sql_ex.init() on success returns the pointer to the first byte after - the sql_ex structure, which is the start of field lengths array. - */ - if (!(field_lens=(uchar*)sql_ex.init((char*)buf + body_offset, - buf_end, - buf[EVENT_TYPE_OFFSET] != LOAD_EVENT))) - return 1; - - data_len = event_len - body_offset; - if (num_fields > data_len) // simple sanity check against corruption - return 1; - for (uint i = 0; i < num_fields; i++) - field_block_len += (uint)field_lens[i] + 1; - - fields = (char*)field_lens + num_fields; - table_name = fields + field_block_len; - db = table_name + table_name_len + 1; - fname = db + db_len + 1; - fname_len = strlen(fname); - // null termination is accomplished by the caller doing buf[event_len]=0 - return 0; -} - -#ifdef MYSQL_CLIENT - -void Load_log_event::print(FILE* file, bool short_form, char* last_db) -{ - if (!short_form) - { - print_header(file); - fprintf(file, "\tQuery\tthread_id=%ld\texec_time=%ld\n", - thread_id, exec_time); - } - - bool same_db = 0; - if (db && last_db) - { - if (!(same_db = !memcmp(last_db, db, db_len + 1))) - memcpy(last_db, db, db_len + 1); - } - - if (db && db[0] && !same_db) - fprintf(file, "use %s;\n", db); - - fprintf(file, "LOAD DATA INFILE '%-*s' ", fname_len, fname); - - if (sql_ex.opt_flags && REPLACE_FLAG ) - fprintf(file," REPLACE "); - else if (sql_ex.opt_flags && IGNORE_FLAG ) - fprintf(file," IGNORE "); - - fprintf(file, "INTO TABLE %s ", table_name); - if (sql_ex.field_term) - { - fprintf(file, " FIELDS TERMINATED BY "); - pretty_print_str(file, sql_ex.field_term, sql_ex.field_term_len); - } - - if (sql_ex.enclosed) - { - if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) - fprintf(file," OPTIONALLY "); - fprintf(file, " ENCLOSED BY "); - pretty_print_str(file, sql_ex.enclosed, sql_ex.enclosed_len); - } - - if (sql_ex.escaped) - { - fprintf(file, " ESCAPED BY "); - pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len); - } - - if (sql_ex.line_term) - { - fprintf(file," LINES TERMINATED BY "); - pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len); - } - - if (sql_ex.line_start) - { - fprintf(file," LINES STARTING BY "); - 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 (num_fields) - { - uint i; - const char* field = fields; - fprintf(file, " ("); - for (i = 0; i < num_fields; i++) - { - if (i) - fputc(',', file); - fprintf(file, field); - - field += field_lens[i] + 1; - } - fputc(')', file); - } - - fprintf(file, ";\n"); -} - -#endif /* #ifdef MYSQL_CLIENT */ - -#ifndef MYSQL_CLIENT - -void Log_event::set_log_pos(MYSQL_LOG* log) -{ - if (!log_pos) - log_pos = my_b_tell(&log->log_file); -} - - -void Load_log_event::set_fields(List &fields) -{ - uint i; - const char* field = this->fields; - for (i = 0; i < num_fields; i++) - { - fields.push_back(new Item_field(db, table_name, field)); - field += field_lens[i] + 1; - } -} - - -Slave_log_event::Slave_log_event(THD* thd_arg, - struct st_relay_log_info* rli): - Log_event(thd_arg),mem_pool(0),master_host(0) -{ - DBUG_ENTER("Slave_log_event"); - if (!rli->inited) // QQ When can this happen ? - DBUG_VOID_RETURN; - - MASTER_INFO* mi = rli->mi; - // TODO: re-write this better without holding both locks at the same time - pthread_mutex_lock(&mi->data_lock); - pthread_mutex_lock(&rli->data_lock); - master_host_len = strlen(mi->host); - master_log_len = strlen(rli->master_log_name); - // on OOM, just do not initialize the structure and print the error - if ((mem_pool = (char*)my_malloc(get_data_size() + 1, - MYF(MY_WME)))) - { - master_host = mem_pool + SL_MASTER_HOST_OFFSET ; - memcpy(master_host, mi->host, master_host_len + 1); - master_log = master_host + master_host_len + 1; - memcpy(master_log, rli->master_log_name, master_log_len + 1); - master_port = mi->port; - master_pos = rli->master_log_pos; - DBUG_PRINT("info", ("master_log: %s pos: %d", master_log, - (ulong) master_pos)); - } - else - sql_print_error("Out of memory while recording slave event"); - pthread_mutex_unlock(&rli->data_lock); - pthread_mutex_unlock(&mi->data_lock); - DBUG_VOID_RETURN; -} - -#endif /* ! MYSQL_CLIENT */ - - -Slave_log_event::~Slave_log_event() -{ - my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR)); -} - -#ifdef MYSQL_CLIENT - -void Slave_log_event::print(FILE* file, bool short_form, char* last_db) -{ - char llbuff[22]; - if (short_form) - return; - print_header(file); - fputc('\n', file); - fprintf(file, "Slave: master_host: '%s' master_port: %d \ -master_log: '%s' master_pos: %s\n", - master_host, master_port, master_log, llstr(master_pos, llbuff)); -} - -#endif /* MYSQL_CLIENT */ - -int Slave_log_event::get_data_size() -{ - return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET; -} - -int Slave_log_event::write_data(IO_CACHE* file) -{ - int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos); - int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port); - // log and host are already there - return my_b_safe_write(file, (byte*)mem_pool, get_data_size()); -} - - -void Slave_log_event::init_from_mem_pool(int data_size) -{ - master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET); - master_port = uint2korr(mem_pool + SL_MASTER_PORT_OFFSET); - master_host = mem_pool + SL_MASTER_HOST_OFFSET; - master_host_len = strlen(master_host); - // safety - master_log = master_host + master_host_len + 1; - if (master_log > mem_pool + data_size) - { - master_host = 0; - return; - } - master_log_len = strlen(master_log); -} - -Slave_log_event::Slave_log_event(const char* buf, int event_len) - :Log_event(buf,0),mem_pool(0),master_host(0) -{ - event_len -= LOG_EVENT_HEADER_LEN; - if (event_len < 0) - return; - if (!(mem_pool = (char*) my_malloc(event_len + 1, MYF(MY_WME)))) - return; - memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len); - mem_pool[event_len] = 0; - init_from_mem_pool(event_len); -} - -#ifndef MYSQL_CLIENT -Create_file_log_event::Create_file_log_event(THD* thd_arg, sql_exchange* ex, - const char* db_arg, const char* table_name_arg, - List& fields_arg, enum enum_duplicates handle_dup, - char* block_arg, uint block_len_arg) - :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup), - fake_base(0),block(block_arg),block_len(block_len_arg), - file_id(thd_arg->file_id = mysql_bin_log.next_file_id()) -{ - sql_ex.force_new_format(); -} -#endif - -int Create_file_log_event::write_data_body(IO_CACHE* file) -{ - int res; - if ((res = Load_log_event::write_data_body(file)) || fake_base) - return res; - return (my_b_safe_write(file, (byte*) "", 1) || - my_b_safe_write(file, (byte*) block, block_len)); -} - -int Create_file_log_event::write_data_header(IO_CACHE* file) -{ - int res; - if ((res = Load_log_event::write_data_header(file)) || fake_base) - return res; - byte buf[CREATE_FILE_HEADER_LEN]; - int4store(buf + CF_FILE_ID_OFFSET, file_id); - return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN); -} - -int Create_file_log_event::write_base(IO_CACHE* file) -{ - int res; - fake_base = 1; // pretend we are Load event - res = write(file); - fake_base = 0; - return res; -} - -Create_file_log_event::Create_file_log_event(const char* buf, int len, - bool old_format) - :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0) -{ - int block_offset; - if (copy_log_event(buf,len,old_format)) - return; - if (!old_format) - { - file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + - + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET); - // + 1 for \0 terminating fname - block_offset = (LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() + - CREATE_FILE_HEADER_LEN + 1); - if (len < block_offset) - return; - block = (char*)buf + block_offset; - block_len = len - block_offset; - } - else - { - sql_ex.force_new_format(); - inited_from_old = 1; - } -} - - -#ifdef MYSQL_CLIENT -void Create_file_log_event::print(FILE* file, bool short_form, - char* last_db) -{ - if (short_form) - return; - Load_log_event::print(file, 1, last_db); - fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); -} -#endif - -#ifndef MYSQL_CLIENT -void Create_file_log_event::pack_info(String* packet) -{ - char buf1[256],buf[22], *end; - String tmp(buf1, sizeof(buf1), system_charset_info); - tmp.length(0); - tmp.append("db="); - tmp.append(db, db_len); - tmp.append(";table="); - tmp.append(table_name, table_name_len); - tmp.append(";file_id="); - end= int10_to_str((long) file_id, buf, 10); - tmp.append(buf, (uint32) (end-buf)); - tmp.append(";block_len="); - end= int10_to_str((long) block_len, buf, 10); - tmp.append(buf, (uint32) (end-buf)); - net_store_data(packet, (char*) tmp.ptr(), tmp.length()); -} -#endif - -#ifndef MYSQL_CLIENT -Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, - uint block_len_arg) - :Log_event(thd_arg), block(block_arg),block_len(block_len_arg), - file_id(thd_arg->file_id) -{ -} -#endif - - -Append_block_log_event::Append_block_log_event(const char* buf, int len) - :Log_event(buf, 0),block(0) -{ - if ((uint)len < APPEND_BLOCK_EVENT_OVERHEAD) - return; - file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); - block = (char*)buf + APPEND_BLOCK_EVENT_OVERHEAD; - block_len = len - APPEND_BLOCK_EVENT_OVERHEAD; -} - -int Append_block_log_event::write_data(IO_CACHE* file) -{ - byte buf[APPEND_BLOCK_HEADER_LEN]; - int4store(buf + AB_FILE_ID_OFFSET, file_id); - return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) || - my_b_safe_write(file, (byte*) block, block_len)); -} - -#ifdef MYSQL_CLIENT -void Append_block_log_event::print(FILE* file, bool short_form, - char* last_db) -{ - if (short_form) - return; - print_header(file); - fputc('\n', file); - fprintf(file, "#Append_block: file_id: %d block_len: %d\n", - file_id, block_len); -} -#endif - -#ifndef MYSQL_CLIENT -void Append_block_log_event::pack_info(String* packet) -{ - char buf[256]; - uint length; - length= (uint) my_sprintf(buf, - (buf, ";file_id=%u;block_len=%u", file_id, - block_len)); - net_store_data(packet, buf, (int32) length); -} - - -Delete_file_log_event::Delete_file_log_event(THD* thd_arg) - :Log_event(thd_arg),file_id(thd_arg->file_id) -{ -} -#endif - - -Delete_file_log_event::Delete_file_log_event(const char* buf, int len) - :Log_event(buf, 0),file_id(0) -{ - if ((uint)len < DELETE_FILE_EVENT_OVERHEAD) - return; - file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); -} - - -int Delete_file_log_event::write_data(IO_CACHE* file) -{ - byte buf[DELETE_FILE_HEADER_LEN]; - int4store(buf + DF_FILE_ID_OFFSET, file_id); - return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN); -} - -#ifdef MYSQL_CLIENT -void Delete_file_log_event::print(FILE* file, bool short_form, - char* last_db) -{ - if (short_form) - return; - print_header(file); - fputc('\n', file); - fprintf(file, "#Delete_file: file_id=%u\n", file_id); -} -#endif - -#ifndef MYSQL_CLIENT -void Delete_file_log_event::pack_info(String* packet) -{ - char buf[64]; - uint length; - length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); - net_store_data(packet, buf, (int32) length); -} -#endif - - -#ifndef MYSQL_CLIENT -Execute_load_log_event::Execute_load_log_event(THD* thd_arg) - :Log_event(thd_arg),file_id(thd_arg->file_id) -{ -} -#endif - - -Execute_load_log_event::Execute_load_log_event(const char* buf,int len) - :Log_event(buf, 0),file_id(0) -{ - if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD) - return; - file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET); -} - - -int Execute_load_log_event::write_data(IO_CACHE* file) -{ - byte buf[EXEC_LOAD_HEADER_LEN]; - int4store(buf + EL_FILE_ID_OFFSET, file_id); - return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN); -} - -#ifdef MYSQL_CLIENT -void Execute_load_log_event::print(FILE* file, bool short_form, - char* last_db) -{ - if (short_form) - return; - print_header(file); - fputc('\n', file); - fprintf(file, "#Exec_load: file_id=%d\n", - file_id); -} -#endif -#ifndef MYSQL_CLIENT -void Execute_load_log_event::pack_info(String* packet) -{ - char buf[64]; - uint length; - length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); - net_store_data(packet, buf, (int32) length); -} -#endif - #ifndef MYSQL_CLIENT int Query_log_event::exec_event(struct st_relay_log_info* rli) { @@ -1764,8 +907,507 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) free_root(&thd->mem_root,0); return Log_event::exec_event(rli); } +#endif // !MYSQL_CLIENT +/***************************************************************************** + ***************************************************************************** + + Start_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Start_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Start_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + char buf[22]; + + tmp.append("Server ver: "); + tmp.append(server_version); + tmp.append(", Binlog ver: "); + tmp.append(llstr(binlog_version, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Start_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Start_log_event::print(FILE* file, bool short_form, char* last_db) +{ + if (short_form) + return; + + print_header(file); + fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, + server_version); + print_timestamp(file, (time_t*)&created); + fputc('\n', file); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Start_log_event::Start_log_event() + + ****************************************************************************/ +Start_log_event::Start_log_event(const char* buf, + bool old_format) + :Log_event(buf, old_format) +{ + buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET); + memcpy(server_version, buf+ST_SERVER_VER_OFFSET, + ST_SERVER_VER_LEN); + created = uint4korr(buf+ST_CREATED_OFFSET); +} + +/***************************************************************************** + + Start_log_event::write_data() + + ****************************************************************************/ +int Start_log_event::write_data(IO_CACHE* file) +{ + char buff[START_HEADER_LEN]; + int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version); + memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN); + int4store(buff + ST_CREATED_OFFSET,created); + return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); +} + +/***************************************************************************** + + Start_log_event::exec_event() + + The master started + + IMPLEMENTATION + - To handle the case where the master died without a stop event, + we clean up all temporary tables + locks that we got. + + TODO + - Remove all active user locks + - 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. + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Start_log_event::exec_event(struct st_relay_log_info* rli) +{ + /* All temporary tables was deleted on the master */ + close_temporary_tables(thd); + /* + If we have old format, load_tmpdir is cleaned up by the I/O thread + */ + if (!rli->mi->old_format) + cleanup_load_tmpdir(); + return Log_event::exec_event(rli); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Load_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Load_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Load_log_event::pack_info(String* packet) +{ + char buf[256]; + String tmp(buf, sizeof(buf), system_charset_info); + tmp.length(0); + if (db && db_len) + { + tmp.append("use "); + tmp.append(db, db_len); + tmp.append("; ", 2); + } + + tmp.append("LOAD DATA INFILE '"); + tmp.append(fname, fname_len); + tmp.append("' ", 2); + if (sql_ex.opt_flags && REPLACE_FLAG ) + tmp.append(" REPLACE "); + else if (sql_ex.opt_flags && IGNORE_FLAG ) + tmp.append(" IGNORE "); + + tmp.append("INTO TABLE "); + tmp.append(table_name); + if (sql_ex.field_term_len) + { + tmp.append(" FIELDS TERMINATED BY "); + pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len); + } + + if (sql_ex.enclosed_len) + { + if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) + tmp.append(" OPTIONALLY "); + tmp.append( " ENCLOSED BY "); + pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len); + } + + if (sql_ex.escaped_len) + { + tmp.append( " ESCAPED BY "); + pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); + } + + if (sql_ex.line_term_len) + { + tmp.append(" LINES TERMINATED BY "); + pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); + } + + if (sql_ex.line_start_len) + { + tmp.append(" LINES STARTING BY "); + pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); + } + + if ((int)skip_lines > 0) + tmp.append( " IGNORE %ld LINES ", (long) skip_lines); + + if (num_fields) + { + uint i; + const char* field = fields; + tmp.append(" ("); + for (i = 0; i < num_fields; i++) + { + if (i) + tmp.append(" ,"); + tmp.append( field); + + field += field_lens[i] + 1; + } + tmp.append(')'); + } + + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Load_log_event::write_data_header() + + ****************************************************************************/ +int Load_log_event::write_data_header(IO_CACHE* file) +{ + char buf[LOAD_HEADER_LEN]; + int4store(buf + L_THREAD_ID_OFFSET, thread_id); + int4store(buf + L_EXEC_TIME_OFFSET, exec_time); + int4store(buf + L_SKIP_LINES_OFFSET, skip_lines); + buf[L_TBL_LEN_OFFSET] = (char)table_name_len; + buf[L_DB_LEN_OFFSET] = (char)db_len; + int4store(buf + L_NUM_FIELDS_OFFSET, num_fields); + return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN); +} + +/***************************************************************************** + + Load_log_event::write_data_body() + + ****************************************************************************/ +int Load_log_event::write_data_body(IO_CACHE* file) +{ + if (sql_ex.write_data(file)) + return 1; + if (num_fields && fields && field_lens) + { + if (my_b_safe_write(file, (byte*)field_lens, num_fields) || + my_b_safe_write(file, (byte*)fields, field_block_len)) + return 1; + } + return (my_b_safe_write(file, (byte*)table_name, table_name_len + 1) || + my_b_safe_write(file, (byte*)db, db_len + 1) || + my_b_safe_write(file, (byte*)fname, fname_len)); +} + +/***************************************************************************** + + Load_log_event::Load_log_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +Load_log_event::Load_log_event(THD* thd, sql_exchange* ex, + const char* db_arg, const char* table_name_arg, + List& fields_arg, + enum enum_duplicates handle_dup) + :Log_event(thd),thread_id(thd->thread_id), num_fields(0),fields(0), + field_lens(0),field_block_len(0), + table_name(table_name_arg ? table_name_arg : ""), + db(db_arg), fname(ex->file_name) +{ + time_t end_time; + time(&end_time); + exec_time = (ulong) (end_time - thd->start_time); + /* db can never be a zero pointer in 4.0 */ + db_len = (uint32) strlen(db); + table_name_len = (uint32) strlen(table_name); + fname_len = (fname) ? (uint) strlen(fname) : 0; + sql_ex.field_term = (char*) ex->field_term->ptr(); + sql_ex.field_term_len = (uint8) ex->field_term->length(); + sql_ex.enclosed = (char*) ex->enclosed->ptr(); + sql_ex.enclosed_len = (uint8) ex->enclosed->length(); + sql_ex.line_term = (char*) ex->line_term->ptr(); + sql_ex.line_term_len = (uint8) ex->line_term->length(); + sql_ex.line_start = (char*) ex->line_start->ptr(); + sql_ex.line_start_len = (uint8) ex->line_start->length(); + sql_ex.escaped = (char*) ex->escaped->ptr(); + sql_ex.escaped_len = (uint8) ex->escaped->length(); + sql_ex.opt_flags = 0; + sql_ex.cached_new_format = -1; + + if (ex->dumpfile) + sql_ex.opt_flags |= DUMPFILE_FLAG; + if (ex->opt_enclosed) + sql_ex.opt_flags |= OPT_ENCLOSED_FLAG; + + sql_ex.empty_flags = 0; + + switch (handle_dup) { + case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break; + case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break; + case DUP_ERROR: break; + } + + if (!ex->field_term->length()) + sql_ex.empty_flags |= FIELD_TERM_EMPTY; + if (!ex->enclosed->length()) + sql_ex.empty_flags |= ENCLOSED_EMPTY; + if (!ex->line_term->length()) + sql_ex.empty_flags |= LINE_TERM_EMPTY; + if (!ex->line_start->length()) + sql_ex.empty_flags |= LINE_START_EMPTY; + if (!ex->escaped->length()) + sql_ex.empty_flags |= ESCAPED_EMPTY; + + skip_lines = ex->skip_lines; + + List_iterator li(fields_arg); + field_lens_buf.length(0); + fields_buf.length(0); + Item* item; + while ((item = li++)) + { + num_fields++; + uchar len = (uchar) strlen(item->name); + field_block_len += len + 1; + fields_buf.append(item->name, len + 1); + field_lens_buf.append((char*)&len, 1); + } + + field_lens = (const uchar*)field_lens_buf.ptr(); + fields = fields_buf.ptr(); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Load_log_event::Load_log_event() + + The caller must do buf[event_len] = 0 before he starts using the + constructed event. + + ****************************************************************************/ +Load_log_event::Load_log_event(const char* buf, int event_len, + bool old_format): + Log_event(buf, old_format),num_fields(0),fields(0), + field_lens(0),field_block_len(0), + table_name(0),db(0),fname(0) +{ + if (!event_len) // derived class, will call copy_log_event() itself + return; + copy_log_event(buf, event_len, old_format); +} + +/***************************************************************************** + + Load_log_event::copy_log_event() + + ****************************************************************************/ +int Load_log_event::copy_log_event(const char *buf, ulong event_len, + bool old_format) +{ + uint data_len; + char* buf_end = (char*)buf + event_len; + const char* data_head = buf + ((old_format) ? + OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN); + thread_id = uint4korr(data_head + L_THREAD_ID_OFFSET); + exec_time = uint4korr(data_head + L_EXEC_TIME_OFFSET); + skip_lines = uint4korr(data_head + L_SKIP_LINES_OFFSET); + table_name_len = (uint)data_head[L_TBL_LEN_OFFSET]; + db_len = (uint)data_head[L_DB_LEN_OFFSET]; + num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET); + + int body_offset = ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ? + LOAD_HEADER_LEN + OLD_HEADER_LEN : + get_data_body_offset()); + + if ((int) event_len < body_offset) + return 1; + /* + Sql_ex.init() on success returns the pointer to the first byte after + the sql_ex structure, which is the start of field lengths array. + */ + if (!(field_lens=(uchar*)sql_ex.init((char*)buf + body_offset, + buf_end, + buf[EVENT_TYPE_OFFSET] != LOAD_EVENT))) + return 1; + + data_len = event_len - body_offset; + if (num_fields > data_len) // simple sanity check against corruption + return 1; + for (uint i = 0; i < num_fields; i++) + field_block_len += (uint)field_lens[i] + 1; + + fields = (char*)field_lens + num_fields; + table_name = fields + field_block_len; + db = table_name + table_name_len + 1; + fname = db + db_len + 1; + fname_len = strlen(fname); + // null termination is accomplished by the caller doing buf[event_len]=0 + return 0; +} + +/***************************************************************************** + + Load_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Load_log_event::print(FILE* file, bool short_form, char* last_db) +{ + if (!short_form) + { + print_header(file); + fprintf(file, "\tQuery\tthread_id=%ld\texec_time=%ld\n", + thread_id, exec_time); + } + + bool same_db = 0; + if (db && last_db) + { + if (!(same_db = !memcmp(last_db, db, db_len + 1))) + memcpy(last_db, db, db_len + 1); + } + + if (db && db[0] && !same_db) + fprintf(file, "use %s;\n", db); + + fprintf(file, "LOAD DATA INFILE '%-*s' ", fname_len, fname); + + if (sql_ex.opt_flags && REPLACE_FLAG ) + fprintf(file," REPLACE "); + else if (sql_ex.opt_flags && IGNORE_FLAG ) + fprintf(file," IGNORE "); + + fprintf(file, "INTO TABLE %s ", table_name); + if (sql_ex.field_term) + { + fprintf(file, " FIELDS TERMINATED BY "); + pretty_print_str(file, sql_ex.field_term, sql_ex.field_term_len); + } + + if (sql_ex.enclosed) + { + if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) + fprintf(file," OPTIONALLY "); + fprintf(file, " ENCLOSED BY "); + pretty_print_str(file, sql_ex.enclosed, sql_ex.enclosed_len); + } + + if (sql_ex.escaped) + { + fprintf(file, " ESCAPED BY "); + pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len); + } + + if (sql_ex.line_term) + { + fprintf(file," LINES TERMINATED BY "); + pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len); + } + + if (sql_ex.line_start) + { + fprintf(file," LINES STARTING BY "); + 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 (num_fields) + { + uint i; + const char* field = fields; + fprintf(file, " ("); + for (i = 0; i < num_fields; i++) + { + if (i) + fputc(',', file); + fprintf(file, field); + + field += field_lens[i] + 1; + } + fputc(')', file); + } + + fprintf(file, ";\n"); +} +#endif /* #ifdef MYSQL_CLIENT */ + +/***************************************************************************** + + Load_log_event::set_fields() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Load_log_event::set_fields(List &fields) +{ + uint i; + const char* field = this->fields; + for (i = 0; i < num_fields; i++) + { + fields.push_back(new Item_field(db, table_name, field)); + field += field_lens[i] + 1; + } +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Load_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) { init_sql_alloc(&thd->mem_root, 8192,0); @@ -1875,43 +1517,573 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) return Log_event::exec_event(rli); } +#endif // !MYSQL_CLIENT -/* - The master started +/***************************************************************************** + ***************************************************************************** - IMPLEMENTATION - - To handle the case where the master died without a stop event, - we clean up all temporary tables + locks that we got. + Rotate_log_event methods - TODO - - Remove all active user locks - - 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. -*/ + ***************************************************************************** + ****************************************************************************/ -int Start_log_event::exec_event(struct st_relay_log_info* rli) +/***************************************************************************** + + Rotate_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Rotate_log_event::pack_info(String* packet) { - /* All temporary tables was deleted on the master */ - close_temporary_tables(thd); - /* - If we have old format, load_tmpdir is cleaned up by the I/O thread - */ - if (!rli->mi->old_format) - cleanup_load_tmpdir(); - return Log_event::exec_event(rli); + char buf1[256], buf[22]; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append(new_log_ident, ident_len); + tmp.append(";pos="); + tmp.append(llstr(pos,buf)); + if (flags & LOG_EVENT_FORCED_ROTATE_F) + tmp.append("; forced by master"); + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Rotate_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char buf[22]; + if (short_form) + return; + + print_header(file); + fprintf(file, "\tRotate to "); + if (new_log_ident) + my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, + MYF(MY_NABP | MY_WME)); + fprintf(file, " pos: %s", llstr(pos, buf)); + if (flags & LOG_EVENT_FORCED_ROTATE_F) + fprintf(file," forced by master"); + fputc('\n', file); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Rotate_log_event::Rotate_log_event() + + ****************************************************************************/ +Rotate_log_event::Rotate_log_event(const char* buf, int event_len, + bool old_format) + :Log_event(buf, old_format),new_log_ident(NULL),alloced(0) +{ + // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET + int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + uint ident_offset; + if (event_len < header_size) + return; + buf += header_size; + if (old_format) + { + ident_len = (uint)(event_len - OLD_HEADER_LEN); + pos = 4; + ident_offset = 0; + } + else + { + ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD); + pos = uint8korr(buf + R_POS_OFFSET); + ident_offset = ROTATE_HEADER_LEN; + } + set_if_smaller(ident_len,FN_REFLEN-1); + if (!(new_log_ident= my_strdup_with_length((byte*) buf + + ident_offset, + (uint) ident_len, + MYF(MY_WME)))) + return; + alloced = 1; } +/***************************************************************************** + + Rotate_log_event::write_data() + + ****************************************************************************/ +int Rotate_log_event::write_data(IO_CACHE* file) +{ + char buf[ROTATE_HEADER_LEN]; + int8store(buf, pos + R_POS_OFFSET); + return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) || + my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); +} + +/***************************************************************************** + + Rotate_log_event::exec_event() + + Got a rotate log even from the master + + IMPLEMENTATION + This is mainly used so that we can later figure out the logname and + position for the master. + + We can't rotate the slave as this will cause infinitive rotations + in a A -> B -> A setup. + + RETURN VALUES + 0 ok + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Rotate_log_event::exec_event(struct st_relay_log_info* rli) +{ + char* log_name = rli->master_log_name; + DBUG_ENTER("Rotate_log_event::exec_event"); + + pthread_mutex_lock(&rli->data_lock); + memcpy(log_name, new_log_ident, ident_len+1); + rli->master_log_pos = pos; + rli->relay_log_pos += get_event_len(); + DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos)); + pthread_mutex_unlock(&rli->data_lock); + pthread_cond_broadcast(&rli->data_cond); + flush_relay_log_info(rli); + DBUG_RETURN(0); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Intvar_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Intvar_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Intvar_log_event::pack_info(String* packet) +{ + char buf1[256], buf[22]; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append(get_var_type_name()); + tmp.append('='); + tmp.append(llstr(val, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Intvar_log_event::Intvar_log_event() + + ****************************************************************************/ +Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) + :Log_event(buf, old_format) +{ + buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + type = buf[I_TYPE_OFFSET]; + val = uint8korr(buf+I_VAL_OFFSET); +} + +/***************************************************************************** + + Intvar_log_event::get_var_type_name() + + ****************************************************************************/ +const char* Intvar_log_event::get_var_type_name() +{ + switch(type) { + case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID"; + case INSERT_ID_EVENT: return "INSERT_ID"; + default: /* impossible */ return "UNKNOWN"; + } +} + +/***************************************************************************** + + Intvar_log_event::write_data() + + ****************************************************************************/ +int Intvar_log_event::write_data(IO_CACHE* file) +{ + char buf[9]; + buf[I_TYPE_OFFSET] = type; + int8store(buf + I_VAL_OFFSET, val); + return my_b_safe_write(file, (byte*) buf, sizeof(buf)); +} + +/***************************************************************************** + + Intvar_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char llbuff[22]; + const char *msg; + LINT_INIT(msg); + + if (!short_form) + { + print_header(file); + fprintf(file, "\tIntvar\n"); + } + + fprintf(file, "SET "); + switch (type) { + case LAST_INSERT_ID_EVENT: + msg="LAST_INSERT_ID"; + break; + case INSERT_ID_EVENT: + msg="INSERT_ID"; + break; + } + fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Intvar_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Intvar_log_event::exec_event(struct st_relay_log_info* rli) +{ + switch (type) { + case LAST_INSERT_ID_EVENT: + thd->last_insert_id_used = 1; + thd->last_insert_id = val; + break; + case INSERT_ID_EVENT: + thd->next_insert_id = val; + break; + } + rli->inc_pending(get_event_len()); + return 0; +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Rand_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Rand_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +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()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Rand_log_event::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); +} + +/***************************************************************************** + + Rand_log_event::write_data() + + ****************************************************************************/ +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)); +} + +/***************************************************************************** + + Rand_log_event::print() + + ****************************************************************************/ +#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 // MYSQL_CLIENT + +/***************************************************************************** + + Rand_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +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; +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Slave_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Slave_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Slave_log_event::pack_info(String* packet) +{ + char buf1[256], buf[22], *end; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append("host="); + tmp.append(master_host); + tmp.append(",port="); + end= int10_to_str((long) master_port, buf, 10); + tmp.append(buf, (uint32) (end-buf)); + tmp.append(",log="); + tmp.append(master_log); + tmp.append(",pos="); + tmp.append(llstr(master_pos,buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Slave_log_event::Slave_log_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +Slave_log_event::Slave_log_event(THD* thd_arg, + struct st_relay_log_info* rli): + Log_event(thd_arg),mem_pool(0),master_host(0) +{ + DBUG_ENTER("Slave_log_event"); + if (!rli->inited) // QQ When can this happen ? + DBUG_VOID_RETURN; + + MASTER_INFO* mi = rli->mi; + // TODO: re-write this better without holding both locks at the same time + pthread_mutex_lock(&mi->data_lock); + pthread_mutex_lock(&rli->data_lock); + master_host_len = strlen(mi->host); + master_log_len = strlen(rli->master_log_name); + // on OOM, just do not initialize the structure and print the error + if ((mem_pool = (char*)my_malloc(get_data_size() + 1, + MYF(MY_WME)))) + { + master_host = mem_pool + SL_MASTER_HOST_OFFSET ; + memcpy(master_host, mi->host, master_host_len + 1); + master_log = master_host + master_host_len + 1; + memcpy(master_log, rli->master_log_name, master_log_len + 1); + master_port = mi->port; + master_pos = rli->master_log_pos; + DBUG_PRINT("info", ("master_log: %s pos: %d", master_log, + (ulong) master_pos)); + } + else + sql_print_error("Out of memory while recording slave event"); + pthread_mutex_unlock(&rli->data_lock); + pthread_mutex_unlock(&mi->data_lock); + DBUG_VOID_RETURN; +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Slave_log_event dtor + + ****************************************************************************/ +Slave_log_event::~Slave_log_event() +{ + my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR)); +} + +/***************************************************************************** + + Slave_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Slave_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char llbuff[22]; + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "Slave: master_host: '%s' master_port: %d \ +master_log: '%s' master_pos: %s\n", + master_host, master_port, master_log, llstr(master_pos, llbuff)); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Slave_log_event::get_data_size() + + ****************************************************************************/ +int Slave_log_event::get_data_size() +{ + return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET; +} + +/***************************************************************************** + + Slave_log_event::write_data() + + ****************************************************************************/ +int Slave_log_event::write_data(IO_CACHE* file) +{ + int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos); + int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port); + // log and host are already there + return my_b_safe_write(file, (byte*)mem_pool, get_data_size()); +} + +/***************************************************************************** + + Slave_log_event::init_from_mem_pool() + + ****************************************************************************/ +void Slave_log_event::init_from_mem_pool(int data_size) +{ + master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET); + master_port = uint2korr(mem_pool + SL_MASTER_PORT_OFFSET); + master_host = mem_pool + SL_MASTER_HOST_OFFSET; + master_host_len = strlen(master_host); + // safety + master_log = master_host + master_host_len + 1; + if (master_log > mem_pool + data_size) + { + master_host = 0; + return; + } + master_log_len = strlen(master_log); +} + +/***************************************************************************** + + Slave_log_event::Slave_log_event() + + ****************************************************************************/ +Slave_log_event::Slave_log_event(const char* buf, int event_len) + :Log_event(buf,0),mem_pool(0),master_host(0) +{ + event_len -= LOG_EVENT_HEADER_LEN; + if (event_len < 0) + return; + if (!(mem_pool = (char*) my_malloc(event_len + 1, MYF(MY_WME)))) + return; + memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len); + mem_pool[event_len] = 0; + init_from_mem_pool(event_len); +} + +/***************************************************************************** + + Slave_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Slave_log_event::exec_event(struct st_relay_log_info* rli) +{ + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + return Log_event::exec_event(rli); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Stop_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Stop_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Stop_log_event::print(FILE* file, bool short_form, char* last_db) +{ + if (short_form) + return; + + print_header(file); + fprintf(file, "\tStop\n"); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Stop_log_event::exec_event() -/* The master stopped. Clean up all temporary tables + locks that the master may have set. TODO - Remove all active user locks -*/ + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Stop_log_event::exec_event(struct st_relay_log_info* rli) { // do not clean up immediately after rotate event @@ -1931,70 +2103,156 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli) flush_relay_log_info(rli); return 0; } +#endif // !MYSQL_CLIENT -/* - Got a rotate log even from the master +/***************************************************************************** + ***************************************************************************** - IMPLEMENTATION - This is mainly used so that we can later figure out the logname and - position for the master. + Create_file_log_event methods - We can't rotate the slave as this will cause infinitive rotations - in a A -> B -> A setup. + ***************************************************************************** + ****************************************************************************/ - RETURN VALUES - 0 ok - */ - +/***************************************************************************** -int Rotate_log_event::exec_event(struct st_relay_log_info* rli) + Create_file_log_event ctor + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +Create_file_log_event::Create_file_log_event(THD* thd_arg, sql_exchange* ex, + const char* db_arg, const char* table_name_arg, + List& fields_arg, enum enum_duplicates handle_dup, + char* block_arg, uint block_len_arg) + :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup), + fake_base(0),block(block_arg),block_len(block_len_arg), + file_id(thd_arg->file_id = mysql_bin_log.next_file_id()) { - char* log_name = rli->master_log_name; - DBUG_ENTER("Rotate_log_event::exec_event"); + sql_ex.force_new_format(); +} +#endif // !MYSQL_CLIENT - pthread_mutex_lock(&rli->data_lock); - memcpy(log_name, new_log_ident, ident_len+1); - rli->master_log_pos = pos; - rli->relay_log_pos += get_event_len(); - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos)); - pthread_mutex_unlock(&rli->data_lock); - pthread_cond_broadcast(&rli->data_cond); - flush_relay_log_info(rli); - DBUG_RETURN(0); +/***************************************************************************** + + Create_file_log_event::write_data_body() + + ****************************************************************************/ +int Create_file_log_event::write_data_body(IO_CACHE* file) +{ + int res; + if ((res = Load_log_event::write_data_body(file)) || fake_base) + return res; + return (my_b_safe_write(file, (byte*) "", 1) || + my_b_safe_write(file, (byte*) block, block_len)); } +/***************************************************************************** -int Intvar_log_event::exec_event(struct st_relay_log_info* rli) + Create_file_log_event::write_data_header() + + ****************************************************************************/ +int Create_file_log_event::write_data_header(IO_CACHE* file) { - switch (type) { - case LAST_INSERT_ID_EVENT: - thd->last_insert_id_used = 1; - thd->last_insert_id = val; - break; - case INSERT_ID_EVENT: - thd->next_insert_id = val; - break; + int res; + if ((res = Load_log_event::write_data_header(file)) || fake_base) + return res; + byte buf[CREATE_FILE_HEADER_LEN]; + int4store(buf + CF_FILE_ID_OFFSET, file_id); + return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN); +} + +/***************************************************************************** + + Create_file_log_event::write_base() + + ****************************************************************************/ +int Create_file_log_event::write_base(IO_CACHE* file) +{ + int res; + fake_base = 1; // pretend we are Load event + res = write(file); + fake_base = 0; + return res; +} + +/***************************************************************************** + + Create_file_log_event ctor + + ****************************************************************************/ +Create_file_log_event::Create_file_log_event(const char* buf, int len, + bool old_format) + :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0) +{ + int block_offset; + if (copy_log_event(buf,len,old_format)) + return; + if (!old_format) + { + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + + + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET); + // + 1 for \0 terminating fname + block_offset = (LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() + + CREATE_FILE_HEADER_LEN + 1); + if (len < block_offset) + return; + block = (char*)buf + block_offset; + block_len = len - block_offset; + } + else + { + sql_ex.force_new_format(); + inited_from_old = 1; } - rli->inc_pending(get_event_len()); - return 0; } -int Rand_log_event::exec_event(struct st_relay_log_info* rli) +/***************************************************************************** + + Create_file_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Create_file_log_event::print(FILE* file, bool short_form, + char* last_db) { - thd->rand.seed1 = seed1; - thd->rand.seed2 = seed2; - rli->inc_pending(get_event_len()); - return 0; + if (short_form) + return; + Load_log_event::print(file, 1, last_db); + fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); } +#endif // MYSQL_CLIENT -int Slave_log_event::exec_event(struct st_relay_log_info* rli) +/***************************************************************************** + + Create_file_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Create_file_log_event::pack_info(String* packet) { - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); - return Log_event::exec_event(rli); + char buf1[256],buf[22], *end; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append("db="); + tmp.append(db, db_len); + tmp.append(";table="); + tmp.append(table_name, table_name_len); + tmp.append(";file_id="); + end= int10_to_str((long) file_id, buf, 10); + tmp.append(buf, (uint32) (end-buf)); + tmp.append(";block_len="); + end= int10_to_str((long) block_len, buf, 10); + tmp.append(buf, (uint32) (end-buf)); + net_store_data(packet, (char*) tmp.ptr(), tmp.length()); } +#endif // !MYSQL_CLIENT +/***************************************************************************** + + Create_file_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Create_file_log_event::exec_event(struct st_relay_log_info* rli) { char fname_buf[FN_REFLEN+10]; @@ -2051,20 +2309,100 @@ err: my_close(fd, MYF(0)); return error ? 1 : Log_event::exec_event(rli); } +#endif // !MYSQL_CLIENT -int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) + +/***************************************************************************** + ***************************************************************************** + + Append_block_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Append_block_log_event ctor + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, + uint block_len_arg) + :Log_event(thd_arg), block(block_arg),block_len(block_len_arg), + file_id(thd_arg->file_id) { - char fname[FN_REFLEN+10]; - char *p= slave_load_file_stem(fname, file_id, server_id); - memcpy(p, ".data", 6); - (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 // !MYSQL_CLIENT + +/***************************************************************************** + + Append_block_log_event ctor + + ****************************************************************************/ +Append_block_log_event::Append_block_log_event(const char* buf, int len) + :Log_event(buf, 0),block(0) +{ + if ((uint)len < APPEND_BLOCK_EVENT_OVERHEAD) + return; + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); + block = (char*)buf + APPEND_BLOCK_EVENT_OVERHEAD; + block_len = len - APPEND_BLOCK_EVENT_OVERHEAD; } +/***************************************************************************** + + Append_block_log_event::write_data() + + ****************************************************************************/ +int Append_block_log_event::write_data(IO_CACHE* file) +{ + byte buf[APPEND_BLOCK_HEADER_LEN]; + int4store(buf + AB_FILE_ID_OFFSET, file_id); + return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) || + my_b_safe_write(file, (byte*) block, block_len)); +} + +/***************************************************************************** + + Append_block_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Append_block_log_event::print(FILE* file, bool short_form, + char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "#Append_block: file_id: %d block_len: %d\n", + file_id, block_len); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Append_block_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Append_block_log_event::pack_info(String* packet) +{ + char buf[256]; + uint length; + length= (uint) my_sprintf(buf, + (buf, ";file_id=%u;block_len=%u", file_id, + block_len)); + net_store_data(packet, buf, (int32) length); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Append_block_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Append_block_log_event::exec_event(struct st_relay_log_info* rli) { char fname[FN_REFLEN+10]; @@ -2092,7 +2430,191 @@ err: my_close(fd, MYF(0)); return error ? error : Log_event::exec_event(rli); } +#endif // !MYSQL_CLIENT + +/***************************************************************************** + ***************************************************************************** + + Delete_file_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Delete_file_log_event ctor + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +Delete_file_log_event::Delete_file_log_event(THD* thd_arg) + :Log_event(thd_arg),file_id(thd_arg->file_id) +{ +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Delete_file_log_event ctor + + ****************************************************************************/ +Delete_file_log_event::Delete_file_log_event(const char* buf, int len) + :Log_event(buf, 0),file_id(0) +{ + if ((uint)len < DELETE_FILE_EVENT_OVERHEAD) + return; + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); +} + +/***************************************************************************** + + Delete_file_log_event::write_data() + + ****************************************************************************/ +int Delete_file_log_event::write_data(IO_CACHE* file) +{ + byte buf[DELETE_FILE_HEADER_LEN]; + int4store(buf + DF_FILE_ID_OFFSET, file_id); + return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN); +} + +/***************************************************************************** + + Delete_file_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Delete_file_log_event::print(FILE* file, bool short_form, + char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "#Delete_file: file_id=%u\n", file_id); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Delete_file_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Delete_file_log_event::pack_info(String* packet) +{ + char buf[64]; + uint length; + length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); + net_store_data(packet, buf, (int32) length); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Delete_file_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) +{ + char fname[FN_REFLEN+10]; + char *p= slave_load_file_stem(fname, file_id, server_id); + memcpy(p, ".data", 6); + (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 // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Execute_load_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Execute_load_log_event ctor + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +Execute_load_log_event::Execute_load_log_event(THD* thd_arg) + :Log_event(thd_arg),file_id(thd_arg->file_id) +{ +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Execute_load_log_event ctor + + ****************************************************************************/ +Execute_load_log_event::Execute_load_log_event(const char* buf,int len) + :Log_event(buf, 0),file_id(0) +{ + if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD) + return; + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET); +} + +/***************************************************************************** + + Execute_load_log_event::write_data() + + ****************************************************************************/ +int Execute_load_log_event::write_data(IO_CACHE* file) +{ + byte buf[EXEC_LOAD_HEADER_LEN]; + int4store(buf + EL_FILE_ID_OFFSET, file_id); + return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN); +} + +/***************************************************************************** + + Execute_load_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Execute_load_log_event::print(FILE* file, bool short_form, + char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "#Exec_load: file_id=%d\n", + file_id); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Execute_load_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Execute_load_log_event::pack_info(String* packet) +{ + char buf[64]; + uint length; + length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); + net_store_data(packet, buf, (int32) length); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Execute_load_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) { char fname[FN_REFLEN+10]; @@ -2151,5 +2673,100 @@ err: } return error ? error : Log_event::exec_event(rli); } +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + sql_ex_info methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + sql_ex_info::write_data() + + ****************************************************************************/ +int sql_ex_info::write_data(IO_CACHE* file) +{ + if (new_format()) + { + return (write_str(file, field_term, field_term_len) || + write_str(file, enclosed, enclosed_len) || + write_str(file, line_term, line_term_len) || + write_str(file, line_start, line_start_len) || + write_str(file, escaped, escaped_len) || + my_b_safe_write(file,(byte*) &opt_flags,1)); + } + else + { + old_sql_ex old_ex; + old_ex.field_term= *field_term; + old_ex.enclosed= *enclosed; + old_ex.line_term= *line_term; + old_ex.line_start= *line_start; + old_ex.escaped= *escaped; + old_ex.opt_flags= opt_flags; + old_ex.empty_flags=empty_flags; + return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex)); + } +} + +/***************************************************************************** + + sql_ex_info::init() + + ****************************************************************************/ +char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) +{ + cached_new_format = use_new_format; + if (use_new_format) + { + empty_flags=0; + /* + The code below assumes that buf will not disappear from + under our feet during the lifetime of the event. This assumption + holds true in the slave thread if the log is in new format, but is not + the case when we have old format because we will be reusing net buffer + to read the actual file before we write out the Create_file event. + */ + if (read_str(buf, buf_end, field_term, field_term_len) || + read_str(buf, buf_end, enclosed, enclosed_len) || + read_str(buf, buf_end, line_term, line_term_len) || + read_str(buf, buf_end, line_start, line_start_len) || + read_str(buf, buf_end, escaped, escaped_len)) + return 0; + opt_flags = *buf++; + } + else + { + field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1; + field_term = buf++; // Use first byte in string + enclosed= buf++; + line_term= buf++; + line_start= buf++; + escaped= buf++; + opt_flags = *buf++; + empty_flags= *buf++; + if (empty_flags & FIELD_TERM_EMPTY) + field_term_len=0; + if (empty_flags & ENCLOSED_EMPTY) + enclosed_len=0; + if (empty_flags & LINE_TERM_EMPTY) + line_term_len=0; + if (empty_flags & LINE_START_EMPTY) + line_start_len=0; + if (empty_flags & ESCAPED_EMPTY) + escaped_len=0; + } + return buf; +} + + + + + + -#endif /* !MYSQL_CLIENT */ diff --git a/sql/log_event.h b/sql/log_event.h index c0a1345647f..bf04c480729 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -54,6 +54,11 @@ #define LINE_START_EMPTY 0x8 #define ESCAPED_EMPTY 0x10 +/***************************************************************************** + + old_sql_ex struct + + ****************************************************************************/ struct old_sql_ex { char field_term; @@ -67,6 +72,11 @@ struct old_sql_ex #define NUM_LOAD_DELIM_STRS 5 +/***************************************************************************** + + sql_ex_info struct + + ****************************************************************************/ struct sql_ex_info { char* field_term; @@ -99,13 +109,19 @@ struct sql_ex_info } }; -/* - Binary log consists of events. Each event has a fixed length header, - followed by possibly variable ( depending on the type of event) length - data body. The data body consists of an optional fixed length segment - (post-header), and an optional variable length segment. See #defines and - comments below for the format specifics -*/ +/***************************************************************************** + + MySQL Binary Log + + This log consists of events. Each event has a fixed-length header, + possibly followed by a variable length data body. + + The data body consists of an optional fixed length segment (post-header) + and an optional variable length segment. + + See the #defines below for the format specifics. + + ****************************************************************************/ /* event-specific post-header sizes */ #define LOG_EVENT_HEADER_LEN 19 @@ -221,6 +237,13 @@ class THD; struct st_relay_log_info; +/***************************************************************************** + + Log_event class + + This is the abstract base class for binary log events. + + ****************************************************************************/ class Log_event { public: @@ -303,6 +326,13 @@ public: }; +/***************************************************************************** + + Query Log Event class + + Logs SQL queries + + ****************************************************************************/ class Query_log_event: public Log_event { protected: @@ -355,6 +385,11 @@ public: }; +/***************************************************************************** + + Slave Log Event class + + ****************************************************************************/ class Slave_log_event: public Log_event { protected: @@ -384,6 +419,12 @@ public: int write_data(IO_CACHE* file ); }; + +/***************************************************************************** + + Load Log Event class + + ****************************************************************************/ class Load_log_event: public Log_event { protected: @@ -446,6 +487,11 @@ public: extern char server_version[SERVER_VERSION_LENGTH]; +/***************************************************************************** + + Start Log Event class + + ****************************************************************************/ class Start_log_event: public Log_event { public: @@ -477,6 +523,13 @@ public: }; +/***************************************************************************** + + Intvar Log Event class + + Logs special variables such as auto_increment values + + ****************************************************************************/ class Intvar_log_event: public Log_event { public: @@ -503,9 +556,11 @@ public: }; /***************************************************************************** - * - * Rand log event class - * + + Rand Log Event class + + Logs random seed used by the next RAND() + ****************************************************************************/ class Rand_log_event: public Log_event { @@ -531,6 +586,12 @@ class Rand_log_event: public Log_event bool is_valid() { return 1; } }; + +/***************************************************************************** + + Stop Log Event class + + ****************************************************************************/ class Stop_log_event: public Log_event { public: @@ -551,6 +612,13 @@ public: }; +/***************************************************************************** + + Rotate Log Event class + + This will be depricated when we move to using sequence ids. + + ****************************************************************************/ class Rotate_log_event: public Log_event { public: @@ -585,6 +653,11 @@ public: /* the classes below are for the new LOAD DATA INFILE logging */ +/***************************************************************************** + + Create File Log Event class + + ****************************************************************************/ class Create_file_log_event: public Load_log_event { protected: @@ -641,6 +714,11 @@ public: }; +/***************************************************************************** + + Append Block Log Event class + + ****************************************************************************/ class Append_block_log_event: public Log_event { public: @@ -665,7 +743,11 @@ public: int write_data(IO_CACHE* file); }; +/***************************************************************************** + Delete File Log Event class + + ****************************************************************************/ class Delete_file_log_event: public Log_event { public: @@ -687,6 +769,11 @@ public: int write_data(IO_CACHE* file); }; +/***************************************************************************** + + Execute Load Log Event class + + ****************************************************************************/ class Execute_load_log_event: public Log_event { public: From 5fbd7b63c5852ceff5558981b56f3b16334223d5 Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Wed, 30 Oct 2002 16:52:12 +0200 Subject: [PATCH 4/8] changes for mysqladmin debug and a bug fix for derived tables --- include/thr_lock.h | 4 ++ mysys/thr_lock.c | 8 ++-- sql/lock.cc | 11 ++++++ sql/sql_derived.cc | 3 +- sql/sql_parse.cc | 10 +++-- sql/sql_test.cc | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 122 insertions(+), 8 deletions(-) diff --git a/include/thr_lock.h b/include/thr_lock.h index 7459849cb04..cf5b0cce4bc 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -74,6 +74,7 @@ typedef struct st_thr_lock_data { enum thr_lock_type type; ulong thread_id; void *status_param; /* Param to status functions */ + void *debug_print_param; } THR_LOCK_DATA; struct st_lock_list { @@ -97,6 +98,9 @@ typedef struct st_thr_lock { } THR_LOCK; +extern LIST *thr_lock_thread_list; +extern pthread_mutex_t THR_LOCK_lock; + my_bool init_thr_lock(void); /* Must be called once/thread */ void thr_lock_init(THR_LOCK *lock); void thr_lock_delete(THR_LOCK *lock); diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 0288c7c1cbe..c796bd1956a 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -91,7 +91,7 @@ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; #define MAX_LOCKS 100 -static LIST *thread_list; /* List of threads in use */ +LIST *thr_lock_thread_list; /* List of threads in use */ ulong max_write_lock_count= ~(ulong) 0L; static inline pthread_cond_t *get_cond(void) @@ -307,7 +307,7 @@ void thr_lock_init(THR_LOCK *lock) pthread_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */ lock->list.data=(void*) lock; - thread_list=list_add(thread_list,&lock->list); + thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list); pthread_mutex_unlock(&THR_LOCK_lock); DBUG_VOID_RETURN; } @@ -318,7 +318,7 @@ void thr_lock_delete(THR_LOCK *lock) DBUG_ENTER("thr_lock_delete"); VOID(pthread_mutex_destroy(&lock->mutex)); pthread_mutex_lock(&THR_LOCK_lock); - thread_list=list_delete(thread_list,&lock->list); + thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list); pthread_mutex_unlock(&THR_LOCK_lock); DBUG_VOID_RETURN; } @@ -1061,7 +1061,7 @@ void thr_print_locks(void) pthread_mutex_lock(&THR_LOCK_lock); puts("Current locks:"); - for (list=thread_list ; list && count++ < MAX_THREADS ; list=rest(list)) + for (list=thr_lock_thread_list ; list && count++ < MAX_THREADS ; list=rest(list)) { THR_LOCK *lock=(THR_LOCK*) list->data; VOID(pthread_mutex_lock(&lock->mutex)); diff --git a/sql/lock.cc b/sql/lock.cc index aed0e1988ea..3b2444c8e9d 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -69,6 +69,12 @@ TODO: #include "mysql_priv.h" #include #include +#include +#ifndef MASTER +#include "../srclib/myisammrg/myrg_def.h" +#else +#include "../myisammrg/myrg_def.h" +#endif extern HASH open_cache; @@ -154,6 +160,7 @@ retry: sql_lock=0; } } + thd->lock_time(); DBUG_RETURN (sql_lock); } @@ -410,8 +417,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, return 0; } } + THR_LOCK_DATA **org_locks = locks; locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE : lock_type); + if (locks) + for ( ; org_locks != locks ; org_locks++) + (*org_locks)->debug_print_param= (void *) table; } return sql_lock; } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 81eade6edb7..9cc83a3835a 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -70,7 +70,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t, if (tables_is_opened || !(res=open_and_lock_tables(thd,tables))) { - if (tables && setup_fields(thd,tables,item_list,0,0,1)) + if (setup_fields(thd,tables,item_list,0,0,1)) { res=-1; goto exit; @@ -113,6 +113,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t, t->table=table; table->derived_select_number= sl->select_number; sl->exclude(); + t->db= (tables && tables->db && tables->db[0]) ? t->db : thd->db; t->derived=(SELECT_LEX *)0; // just in case ... } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ae32cd078f7..0eb7acde9f1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1388,10 +1388,14 @@ mysql_execute_command(THD *thd) for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next) - if (cursor->derived && mysql_derived(thd, lex, + if (cursor->derived && (res=mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, - cursor, 0)) + cursor, 0))) + { + if (res < 0) + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); DBUG_VOID_RETURN; + } } if ((lex->select_lex.next_select_in_list() && lex->unit.create_total_list(thd, lex, &tables)) || @@ -2777,7 +2781,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, found=1; } } - else if (check_access(thd,want_access,tables->db,&tables->grant.privilege, + else if (tables->db && check_access(thd,want_access,tables->db,&tables->grant.privilege, 0, no_errors)) return TRUE; } diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 6ae07417e7d..5aac972e0bb 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -203,6 +203,99 @@ TEST_join(JOIN *join) #endif +typedef struct st_debug_lock +{ + ulong thread_id; + char table_name[FN_REFLEN]; + bool waiting; + const char *lock_text; + enum thr_lock_type type; +} TABLE_LOCK_INFO; + +static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b) +{ + if (a->thread_id > b->thread_id) + return 1; + if (a->thread_id < b->thread_id) + return -1; + if (a->waiting == b->waiting) + return 0; + else if (a->waiting) + return -1; + return 1; +} + +static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data, bool wait, const char *text) +{ + if (data) + { + TABLE *table=(TABLE *)data->debug_print_param; + if (table && table->tmp_table == NO_TMP_TABLE) + { + TABLE_LOCK_INFO table_lock_info; + table_lock_info.thread_id=table->in_use->thread_id; + memcpy(table_lock_info.table_name, table->table_cache_key, table->key_length); + table_lock_info.table_name[strlen(table_lock_info.table_name)]='.'; + table_lock_info.waiting=wait; + table_lock_info.lock_text=text; + table_lock_info.type=table->reginfo.lock_type; // obtainable also from THR_LOCK_DATA + VOID(push_dynamic(ar,(gptr) &table_lock_info)); + } + } +} +/* + Regarding MERGE tables: + +For now, the best option is to use the common TABLE *pointer for all +cases; The drawback is that for MERGE tables we will see many locks +for the merge tables even if some of them are for individual tables. + +The way to solve this is to add to 'THR_LOCK' structure a pointer to +the filename and use this when printing the data. +(We can for now ignore this and just print the same name for all merge +table parts; Please add the above as a comment to the display_lock +function so that we can easily add this if we ever need this. + +*/ + +static void display_table_locks (void) +{ + LIST *list; + DYNAMIC_ARRAY saved_table_locks; + + VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50)); + VOID(pthread_mutex_lock(&THR_LOCK_lock)); + for (list=thr_lock_thread_list ; list ; list=rest(list)) + { + THR_LOCK *lock=(THR_LOCK*) list->data; + + VOID(pthread_mutex_lock(&lock->mutex)); + push_locks_into_array(&saved_table_locks, lock->write.data, false, "Locked - write"); + push_locks_into_array(&saved_table_locks, lock->write_wait.data, true, "Waiting - write"); + push_locks_into_array(&saved_table_locks, lock->read.data, false, "Locked - read"); + push_locks_into_array(&saved_table_locks, lock->read_wait.data, true, "Waiting - read"); + VOID(pthread_mutex_unlock(&lock->mutex)); + } + VOID(pthread_mutex_unlock(&THR_LOCK_lock)); + if (!saved_table_locks.elements) goto end; + + qsort((gptr) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare); + freeze_size(&saved_table_locks); + + puts("\nThread database.table_name Locked/Waiting Lock_type\n"); + + for (uint i=0 ; i < saved_table_locks.elements ; i++) + { + TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*); + printf("%-8ld%-28.28s%-22s%s\n", + dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]); + } + puts("\n\n"); +end: + delete_dynamic(&saved_table_locks); +} + + void mysql_print_status(THD *thd) { char current_dir[FN_REFLEN]; @@ -268,6 +361,7 @@ Next alarm time: %lu\n", alarm_info.max_used_alarms, alarm_info.next_alarm_time); #endif + display_table_locks(); fflush(stdout); if (thd) thd->proc_info="malloc"; From a5fcadce654f6b48eb2dd06c9c7fbab5dcbbf43c Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Wed, 30 Oct 2002 18:23:02 +0200 Subject: [PATCH 5/8] some test cases for the bugs being fixed --- .bzrignore | 3 +++ mysql-test/r/derived.result | 6 ++++++ mysql-test/t/derived.test | 2 ++ 3 files changed, 11 insertions(+) diff --git a/.bzrignore b/.bzrignore index bacfe2ff975..27ee8321289 100644 --- a/.bzrignore +++ b/.bzrignore @@ -513,3 +513,6 @@ innobase/stamp-h1 myisam/rt_test.MYD myisam/rt_test.MYI stamp-h1 +libmysqld/sql_help.cc +scripts/fill_func_tables +scripts/fill_func_tables.sql diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index e05be96c6b7..d3fbd557156 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -18,3 +18,9 @@ a y 3 3 3 3 drop table if exists t1.t2,t3; +select * from (select 1); +1 +1 +select a from (select 1 as a); +a +1 diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 76ef5fba351..87910c29706 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -9,3 +9,5 @@ CREATE TABLE t3 (a int not null, b char (10) not null); insert into t3 values (3,'f'),(4,'y'),(5,'z'),(6,'c'); select t1.a,t4.y from t1,(select t2.a as y from t2,(select t3.b from t3 where t3.a>3) as t5 where t2.b=t5.b) as t4 where t1.a = t4.y; drop table if exists t1.t2,t3; +select * from (select 1); +select a from (select 1 as a); From 9b012db53eb46ad665bed15b307727c4cf497f3e Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Wed, 30 Oct 2002 19:30:57 +0200 Subject: [PATCH 6/8] small fix when building in --without-debug --- sql/sql_test.cc | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 5aac972e0bb..b3bf47e7fd2 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -26,6 +26,23 @@ /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; +static const char *lock_descriptions[] = +{ + "No lock", + "Low priority read lock", + "Shared Read lock", + "High priority read lock", + "Read lock without concurrent inserts", + "Write lock that allows other writers", + "Write lock, but allow reading", + "Concurrent insert lock", + "Lock Used by delayed insert", + "Low priority write lock", + "High priority write lock", + "Highest priority write lock" +}; + + #ifndef DBUG_OFF void @@ -45,29 +62,11 @@ print_where(COND *cond,const char *info) DBUG_UNLOCK_FILE; } } - /* This is for debugging purposes */ extern HASH open_cache; extern TABLE *unused_tables; -static const char *lock_descriptions[] = -{ - "No lock", - "Low priority read lock", - "Shared Read lock", - "High priority read lock", - "Read lock without concurrent inserts", - "Write lock that allows other writers", - "Write lock, but allow reading", - "Concurrent insert lock", - "Lock Used by delayed insert", - "Low priority write lock", - "High priority write lock", - "Highest priority write lock" -}; - - void print_cached_tables(void) { uint idx,count,unused; From 168a489d345f9c1ba7780a0a6b3b7259c003d953 Mon Sep 17 00:00:00 2001 From: "nick@mysql.com" <> Date: Wed, 30 Oct 2002 23:48:04 -0700 Subject: [PATCH 7/8] fix commit thinko --- sql/sql_yacc.yy | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a3fe6dd7b79..7a387d539ff 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1449,20 +1449,6 @@ slave: lex->sql_command = SQLCOM_SLAVE_STOP; lex->type = 0; }; - | - SLAVE START_SYM slave_thread_opts - { - LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_START; - lex->type = 0; - } - | - SLAVE STOP_SYM slave_thread_opts - { - LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_STOP; - lex->type = 0; - }; slave_thread_opts: slave_thread_opt From f013ad57ef7fea6fd6a07ef136fb63f02eb24b28 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Thu, 31 Oct 2002 11:27:52 +0200 Subject: [PATCH 8/8] 30 % faster longlong10_to_str function --- strings/longlong2str-x86.s | 95 +++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/strings/longlong2str-x86.s b/strings/longlong2str-x86.s index 98e60acbafb..3bfd1777e18 100644 --- a/strings/longlong2str-x86.s +++ b/strings/longlong2str-x86.s @@ -64,7 +64,7 @@ longlong2str: jne .L150 movb $48,(%edi) incl %edi - jmp .L164 + jmp .L10_end .align 4 .L150: @@ -81,9 +81,9 @@ longlong2str: movl %eax,%ebp movl %esi,%eax divl %ebx + decl %ecx movl %eax,%esi # quotent in ebp:esi movb _dig_vec(%edx),%al # al is faster than dl - decl %ecx movb %al,(%ecx) # store value in buff .align 4 .L155: @@ -91,7 +91,7 @@ longlong2str: ja .L153 testl %esi,%esi # rest value jl .L153 - je .L160 # Ready + je .L10_mov # Ready movl %esi,%eax movl $_dig_vec,%ebp .align 4 @@ -105,14 +105,14 @@ longlong2str: movb %dl,(%ecx) jne .L154 -.L160: +.L10_mov: movl %ecx,%esi leal 92(%esp),%ecx # End of buffer subl %esi,%ecx rep movsb -.L164: +.L10_end: movl %edi,%eax # Pointer to end null movb $0,(%edi) # Store the end null @@ -131,10 +131,93 @@ longlong2str: .Lfe3: .size longlong2str,.Lfe3-longlong2str +# +# This is almost equal to the above, except that we can do the final +# loop much more efficient +# + + .align 4 +.Ltmp: + .long 0xcccccccd + .align 4 + .globl longlong10_to_str .type longlong10_str,@function longlong10_to_str: - jmp longlong2str + subl $80,%esp + pushl %ebp + pushl %esi + pushl %edi + pushl %ebx + movl 100(%esp),%esi # Lower part of val + movl 104(%esp),%ebp # Higher part of val + movl 108(%esp),%edi # get dst + movl 112(%esp),%ebx # Radix (10 or -10) + testl %ebx,%ebx + jge .L10_10 # Positive radix + + negl %ebx # Change radix to positive (= 10) + + testl %ebp,%ebp # Test if negative value + jge .L10_10 + movb $45,(%edi) # Add sign + incl %edi + negl %esi # Change sign of val (ebp:esi) + adcl $0,%ebp + negl %ebp + .align 4 + +.L10_10: + leal 92(%esp),%ecx # End of buffer + movl %esi,%eax # Test if zero (for easy loop) + orl %ebp,%eax + jne .L10_30 # Not zero + + # Here when value is zero + movb $48,(%edi) + incl %edi + jmp .L10_end + .align 4 + +.L10_20: + # val is stored in in ebp:esi + movl %ebp,%eax # High part of value + xorl %edx,%edx + divl %ebx # Divide by 10 + movl %eax,%ebp + movl %esi,%eax + divl %ebx # Divide by 10 + decl %ecx + movl %eax,%esi # quotent in ebp:esi + addl $48,%edx # Convert to ascii + movb %dl,(%ecx) # store value in buff + +.L10_30: + testl %ebp,%ebp + ja .L10_20 + testl %esi,%esi # rest value + jl .L10_20 # Unsigned, do ulonglong div once more + je .L10_mov # Ready + movl %esi,%ebx # Move val to %ebx + + # The following code uses some tricks to change division by 10 to + # multiplication and shifts + movl .Ltmp,%esi # set %esi to 0xcccccccd + +.L10_40: + movl %ebx,%eax + mull %esi + decl %ecx + shrl $3,%edx + leal (%edx,%edx,4),%eax + addl %eax,%eax + subb %al,%bl # %bl now contains val % 10 + addb $48,%bl + movb %bl,(%ecx) + movl %edx,%ebx + testl %ebx,%ebx + jne .L10_40 + jmp .L10_mov # Shared end with longlong10_to_str .L10end: .size longlong10_to_str,.L10end-longlong10_to_str