diff options
author | unknown <sasha@mysql.sashanet.com> | 2001-06-21 13:19:24 -0600 |
---|---|---|
committer | unknown <sasha@mysql.sashanet.com> | 2001-06-21 13:19:24 -0600 |
commit | 5eefda7a8504d01c0dba8304a0ff3f0fd2910c2c (patch) | |
tree | e0d3ffc83959f6562326765b3d79c7915f033bbf | |
parent | 4564c64a00693a27d7bd5d4d66d67c9eccbcac2a (diff) | |
download | mariadb-git-5eefda7a8504d01c0dba8304a0ff3f0fd2910c2c.tar.gz |
added SHOW BINLOG EVENTS
fixed log sequence bugs
fixed bugs in handling Slave event
added test case with SHOW BINLOG EVENTS
have not fixed all the bugs - found some that are also in 3.23,
will fix them there first, then do pull and cleanup
will not push this changeset
include/mysqld_error.h:
new error
mysql-test/mysql-test-run.sh:
use quotes in expr
sql/lex.h:
SHOW BINLOG EVENTS
sql/log.cc:
fixed log sequence bugs
sql/log_event.cc:
SHOW BINLOG EVENTS
fixed bugs Slave event handling
sql/log_event.h:
SHOW BINLOG EVENTS
sql/share/english/errmsg.txt:
SHOW BINLOG EVENTS
sql/sql_lex.h:
SHOW BINLOG EVENTS
sql/sql_parse.cc:
SHOW BINLOG EVENTS
sql/sql_repl.cc:
SHOW BINLOG EVENTS
sql/sql_repl.h:
SHOW BINLOG EVENTS
sql/sql_yacc.yy:
SHOW BINLOG EVENTS
-rw-r--r-- | include/mysqld_error.h | 3 | ||||
-rw-r--r-- | mysql-test/mysql-test-run.sh | 2 | ||||
-rw-r--r-- | mysql-test/r/rpl_log.result | 51 | ||||
-rw-r--r-- | mysql-test/t/rpl_log.test | 27 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/log.cc | 17 | ||||
-rw-r--r-- | sql/log_event.cc | 235 | ||||
-rw-r--r-- | sql/log_event.h | 27 | ||||
-rw-r--r-- | sql/share/english/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sql_lex.h | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_repl.cc | 102 | ||||
-rw-r--r-- | sql/sql_repl.h | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 19 |
14 files changed, 474 insertions, 24 deletions
diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 5c3d47c2994..42095b953eb 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -210,4 +210,5 @@ #define ER_READ_ONLY_TRANSACTION 1207 #define ER_CONNECT_TO_MASTER 1208 #define ER_QUERY_ON_MASTER 1209 -#define ER_ERROR_MESSAGES 210 +#define ER_SHOW_BINLOG_EVENTS 1210 +#define ER_ERROR_MESSAGES 211 diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index f8916403738..472aa60ffa1 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -659,7 +659,7 @@ run_testcase () slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0` if [ -n $SKIP_TEST ] ; then - SKIP_THIS_TEST=`$EXPR \( $tname : $SKIP_TEST \) != 0` + SKIP_THIS_TEST=`$EXPR \( $tname : '$SKIP_TEST' \) != 0` if [ x$SKIP_THIS_TEST = x1 ] ; then return; diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result new file mode 100644 index 00000000000..c6345b6b9fb --- /dev/null +++ b/mysql-test/r/rpl_log.result @@ -0,0 +1,51 @@ +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 4 Start 1 1 Server ver: 4.0.0-debug-log, Binlog ver: 2 +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 3 INSERT_ID=1 +master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) +master-bin.001 263 Query 1 5 use test; drop table t1 +master-bin.001 311 Query 1 6 use test; create table t1 (word char(20) not null) +master-bin.001 386 Load 1 7 use test; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1 FIELDS TERMINATED BY '\t' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) +master-bin.001 468 Query 1 8 use test; drop table t1 +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 3 INSERT_ID=1 +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 4 Start 1 1 Server ver: 4.0.0-debug-log, Binlog ver: 2 +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 3 INSERT_ID=1 +master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) +master-bin.001 263 Query 1 5 use test; drop table t1 +master-bin.001 311 Query 1 6 use test; create table t1 (word char(20) not null) +master-bin.001 386 Load 1 7 use test; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1 FIELDS TERMINATED BY '\t' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) +master-bin.001 468 Query 1 8 use test; drop table t1 +master-bin.001 516 Rotate 1 9 master-bin.002 +master-bin.001 549 Stop 1 10 +Log_name Pos Event_type Server_id Log_seq Info +master-bin.002 4 Start 1 1 Server ver: 4.0.0-debug-log, Binlog ver: 2 +Log_name +slave-bin.001 +slave-bin.002 +slave-bin.003 +slave-bin.004 +Log_name Pos Event_type Server_id Log_seq Info +slave-bin.001 4 Start 2 1 Server ver: 4.0.0-debug-log, Binlog ver: 2 +slave-bin.001 79 Slave 2 2 +slave-bin.001 118 Rotate 2 3 slave-bin.002 +slave-bin.001 150 Stop 2 4 +Log_name Pos Event_type Server_id Log_seq Info +slave-bin.002 4 Start 2 1 Server ver: 4.0.0-debug-log, Binlog ver: 2 +slave-bin.002 79 Slave 1 2 +slave-bin.002 132 Slave 1 3 +slave-bin.002 185 Query 1 4 use test; create table t1(n int not null auto_increment primary key) +slave-bin.002 278 Intvar 2 5 INSERT_ID=1 +slave-bin.002 306 Query 1 6 use test; insert into t1 values (NULL) +slave-bin.002 369 Query 1 7 use test; drop table t1 +slave-bin.002 417 Query 1 8 use test; create table t1 (word char(20) not null) +slave-bin.002 492 Query 1 9 use test; drop table t1 +slave-bin.002 540 Rotate 2 10 slave-bin.003 +slave-bin.002 572 Stop 2 11 diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test new file mode 100644 index 00000000000..08e6f687cd8 --- /dev/null +++ b/mysql-test/t/rpl_log.test @@ -0,0 +1,27 @@ +source include/master-slave.inc; + +#clean up slave binlogs +connection slave; +reset master; + +connection master; +drop table if exists t1; +create table t1(n int not null auto_increment primary key); +insert into t1 values (NULL); +drop table t1; +create table t1 (word char(20) not null); +load data infile '../../std_data/words.dat' into table t1; +drop table t1; +show binlog events; +show binlog events from 79 limit 1; +show binlog events from 79 limit 2; +show binlog events from 79 limit 2,1; +flush logs; +show binlog events; +show binlog events in 'master-bin.002'; +save_master_pos; +connection slave; +sync_with_master; +show master logs; +show binlog events in 'slave-bin.001' from 4; +show binlog events in 'slave-bin.002' from 4; diff --git a/sql/lex.h b/sql/lex.h index 2f3ae260417..48352d3e702 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -70,6 +70,7 @@ static SYMBOL symbols[] = { { "BIGINT", SYM(BIGINT),0,0}, { "BIT", SYM(BIT_SYM),0,0}, { "BINARY", SYM(BINARY),0,0}, + { "BINLOG", SYM(BINLOG_SYM),0,0}, { "BLOB", SYM(BLOB_SYM),0,0}, { "BOOL", SYM(BOOL_SYM),0,0}, { "BOTH", SYM(BOTH),0,0}, @@ -128,6 +129,7 @@ static SYMBOL symbols[] = { { "ENABLE", SYM(ENABLE_SYM),0,0}, { "ENCLOSED", SYM(ENCLOSED),0,0}, { "ENUM", SYM(ENUM),0,0}, + { "EVENTS", SYM(EVENTS_SYM),0,0}, { "EXPLAIN", SYM(DESCRIBE),0,0}, { "EXISTS", SYM(EXISTS),0,0}, { "EXTENDED", SYM(EXTENDED_SYM),0,0}, diff --git a/sql/log.cc b/sql/log.cc index 1faf9f971be..5ee3120a991 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -230,6 +230,8 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, if ((do_magic && my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4)) || open_index(O_APPEND | O_RDWR | O_CREAT)) goto err; + + log_seq = 1; Start_log_event s; bool error; s.set_log_seq(0, this); @@ -240,10 +242,12 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, { THD* thd = current_thd; Slave_log_event s(thd, &glob_mi); - s.set_log_seq(thd, this); if(s.master_host) + { + s.set_log_seq(thd, this); s.write(&log_file); + } } flush_io_cache(&log_file); @@ -553,7 +557,6 @@ void MYSQL_LOG::new_file() open(old_name, log_type, new_name); my_free(old_name,MYF(0)); last_time=query_start=0; - log_seq = 1; write_error=0; VOID(pthread_mutex_unlock(&LOCK_log)); } @@ -666,8 +669,12 @@ bool MYSQL_LOG::write(Query_log_event* event_info) if (is_open()) { THD *thd=event_info->thd; +#ifdef USING_TRANSACTIONS IO_CACHE *file = (event_info->cache_stmt ? &thd->transaction.trans_log : &log_file); +#else + IO_CACHE *file = &log_file; +#endif if ((!(thd->options & OPTION_BIN_LOG) && (thd->master_access & PROCESS_ACL)) || !db_ok(event_info->db, binlog_do_db, binlog_ignore_db)) @@ -680,12 +687,14 @@ bool MYSQL_LOG::write(Query_log_event* event_info) if (thd->last_insert_id_used) { Intvar_log_event e((uchar)LAST_INSERT_ID_EVENT, thd->last_insert_id); + e.set_log_seq(thd, this); if (e.write(file)) goto err; } if (thd->insert_id_used) { Intvar_log_event e((uchar)INSERT_ID_EVENT, thd->last_insert_id); + e.set_log_seq(thd, this); if (e.write(file)) goto err; } @@ -698,10 +707,12 @@ bool MYSQL_LOG::write(Query_log_event* event_info) // just in case somebody wants it later thd->query_length = (uint)(p - buf); Query_log_event e(thd, buf); + e.set_log_seq(thd, this); if (e.write(file)) goto err; thd->query_length = save_query_length; // clean up } + event_info->set_log_seq(thd, this); if (event_info->write(file) || file == &log_file && flush_io_cache(file)) goto err; @@ -796,6 +807,7 @@ bool MYSQL_LOG::write(Load_log_event* event_info) if ((thd->options & OPTION_BIN_LOG) || !(thd->master_access & PROCESS_ACL)) { + event_info->set_log_seq(thd, this); if (event_info->write(&log_file) || flush_io_cache(&log_file)) { if (!write_error) @@ -947,6 +959,7 @@ void MYSQL_LOG::close(bool exiting) if (log_type == LOG_BIN) { Stop_log_event s; + s.set_log_seq(0, this); s.write(&log_file); VOID(pthread_cond_broadcast(&COND_binlog_update)); } diff --git a/sql/log_event.cc b/sql/log_event.cc index f438eb351d1..bf0875fbb5d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -32,6 +32,7 @@ static void pretty_print_char(FILE* file, int c) case '\r': fprintf(file, "\\r"); break; case '\\': fprintf(file, "\\\\"); break; case '\b': fprintf(file, "\\b"); break; + case '\t': fprintf(file, "\\t"); break; case '\'': fprintf(file, "\\'"); break; case 0 : fprintf(file, "\\0"); break; default: @@ -41,6 +42,203 @@ static void pretty_print_char(FILE* file, int c) fputc('\'', file); } +#ifndef MYSQL_CLIENT + +static void pretty_print_char(String* packet, int c) +{ + packet->append('\''); + switch(c) { + case '\n': packet->append( "\\n"); break; + case '\r': packet->append( "\\r"); break; + case '\\': packet->append( "\\\\"); break; + case '\b': packet->append( "\\b"); break; + case '\t': packet->append( "\\t"); break; + case '\'': packet->append( "\\'"); break; + case 0 : packet->append( "\\0"); break; + default: + packet->append((char)c); + break; + } + packet->append('\''); +} + +#endif + +const char* Log_event::get_type_str() +{ + switch(get_type_code()) + { + case START_EVENT: return "Start"; + case STOP_EVENT: return "Stop"; + case QUERY_EVENT: return "Query"; + case ROTATE_EVENT: return "Rotate"; + case INTVAR_EVENT: return "Intvar"; + case LOAD_EVENT: return "Load"; + case SLAVE_EVENT: return "Slave"; + default: /* impossible */ return "Unknown"; + } +} + +#ifndef MYSQL_CLIENT + +void Log_event::pack_info(String* packet) +{ + net_store_data(packet, "", 0); +} + +void Query_log_event::pack_info(String* packet) +{ + String tmp; + if(db && db_len) + { + tmp.append("use "); + tmp.append(db, db_len); + tmp.append("; ", 2); + } + + 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) +{ + String tmp; + 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) +{ + String tmp; + if(db && db_len) + { + tmp.append("use "); + tmp.append(db, db_len); + tmp.append("; ", 2); + } + + tmp.append("LOAD DATA INFILE '"); + tmp.append(fname); + 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.empty_flags & FIELD_TERM_EMPTY)) + { + tmp.append(" FIELDS TERMINATED BY "); + pretty_print_char(&tmp, sql_ex.field_term); + } + + if (!(sql_ex.empty_flags & ENCLOSED_EMPTY)) + { + if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) + tmp.append(" OPTIONALLY "); + tmp.append( " ENCLOSED BY "); + pretty_print_char(&tmp, sql_ex.enclosed); + } + + if (!(sql_ex.empty_flags & ESCAPED_EMPTY)) + { + tmp.append( " ESCAPED BY "); + pretty_print_char(&tmp, sql_ex.escaped); + } + + if (!(sql_ex.empty_flags & LINE_TERM_EMPTY)) + { + tmp.append(" LINES TERMINATED BY "); + pretty_print_char(&tmp, sql_ex.line_term); + } + + if (!(sql_ex.empty_flags & LINE_START_EMPTY)) + { + tmp.append(" LINES STARTING BY "); + pretty_print_char(&tmp, sql_ex.line_start); + } + + 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) +{ + net_store_data(packet, new_log_ident, ident_len); +} + +void Intvar_log_event::pack_info(String* packet) +{ + String tmp; + char buf[22]; + tmp.append(get_var_type_name()); + tmp.append('='); + tmp.append(llstr(val, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} + +void Slave_log_event::pack_info(String* packet) +{ + net_store_data(packet, "", 0); +} + + +void Log_event::init_show_field_list(List<Item>* field_list) +{ + field_list->push_back(new Item_empty_string("Log_name", 20)); + field_list->push_back(new Item_empty_string("Pos", 20)); + field_list->push_back(new Item_empty_string("Event_type", 20)); + field_list->push_back(new Item_empty_string("Server_id", 20)); + field_list->push_back(new Item_empty_string("Log_seq", 20)); + field_list->push_back(new Item_empty_string("Info", 20)); +} + +int Log_event::net_send(THD* thd, const char* log_name, ulong pos) +{ + String* packet = &thd->packet; + const char* p = strrchr(log_name, FN_LIBCHAR); + const char* event_type; + if (p) + log_name = p + 1; + + packet->length(0); + net_store_data(packet, log_name, strlen(log_name)); + net_store_data(packet, (longlong)pos); + event_type = get_type_str(); + net_store_data(packet, event_type, strlen(event_type)); + net_store_data(packet, server_id); + net_store_data(packet, log_seq); + pack_info(packet); + return my_net_write(&thd->net, (char*)packet->ptr(), packet->length()); +} + +#endif + int Query_log_event::write(IO_CACHE* file) { return query ? Log_event::write(file) : -1; @@ -209,6 +407,17 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len) return r; } + case SLAVE_EVENT: + { + Slave_log_event* s = new Slave_log_event(buf, event_len); + if (!s->master_host) + { + delete s; + return NULL; + } + + return s; + } case START_EVENT: return new Start_log_event(buf); case STOP_EVENT: return new Stop_log_event(buf); case INTVAR_EVENT: return new Intvar_log_event(buf); @@ -394,6 +603,16 @@ Intvar_log_event::Intvar_log_event(const char* buf):Log_event(buf) 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]; @@ -616,8 +835,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg,MASTER_INFO* mi): if((mem_pool = (char*)my_malloc(get_data_size() + 1, MYF(MY_WME)))) { - master_host = mem_pool + sizeof(uint32) + - sizeof(ulonglong) + sizeof(uint16); + 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, mi->log_file_name, master_log_len + 1); @@ -653,19 +871,15 @@ void Slave_log_event::print(FILE* file, bool short_form = 0, int Slave_log_event::get_data_size() { - return master_host_len + master_log_len + 1 + 4 /* data_size*/ + - 8 /* master_pos */ + - 2 /* master_port */; + return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET; } int Slave_log_event::write_data(IO_CACHE* file) { - int data_size = get_data_size(); - int4store(mem_pool, data_size); 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_write(file, (byte*)mem_pool, data_size); + return my_b_write(file, (byte*)mem_pool, get_data_size()); } void Slave_log_event::init_from_mem_pool(int data_size) @@ -694,8 +908,3 @@ Slave_log_event::Slave_log_event(const char* buf, int event_len): mem_pool[event_len] = 0; init_from_mem_pool(event_len); } - - - - - diff --git a/sql/log_event.h b/sql/log_event.h index eef2be962a1..6a597142a2c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -71,9 +71,9 @@ /* slave event post-header */ -#define SL_MASTER_PORT_OFFSET 12 -#define SL_MASTER_POS_OFFSET 4 -#define SL_MASTER_HOST_OFFSET 14 +#define SL_MASTER_PORT_OFFSET 8 +#define SL_MASTER_POS_OFFSET 0 +#define SL_MASTER_HOST_OFFSET 10 /* query event post-header */ @@ -177,11 +177,15 @@ public: // if mutex is 0, the read will proceed without mutex static Log_event* read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock); static Log_event* read_log_event(const char* buf, int event_len); + const char* get_type_str(); #ifndef MYSQL_CLIENT static int read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock); void set_log_seq(THD* thd, MYSQL_LOG* log); + virtual void pack_info(String* packet); + int net_send(THD* thd, const char* log_name, ulong pos); + static void init_show_field_list(List<Item>* field_list); #endif }; @@ -217,6 +221,8 @@ public: exec_time = (ulong) (end_time - thd->start_time); db_len = (db) ? (uint32) strlen(db) : 0; } + + void pack_info(String* packet); #endif Query_log_event(const char* buf, int event_len); @@ -257,6 +263,7 @@ public: #ifndef MYSQL_CLIENT Slave_log_event(THD* thd_arg, struct st_master_info* mi); + void pack_info(String* packet); #endif Slave_log_event(const char* buf, int event_len); @@ -383,6 +390,7 @@ public: fields = fields_buf.ptr(); } void set_fields(List<Item> &fields_arg); + void pack_info(String* packet); #endif Load_log_event(const char* buf, int event_len); @@ -432,6 +440,9 @@ public: { return START_HEADER_LEN; } +#ifndef MYSQL_CLIENT + void pack_info(String* packet); +#endif void print(FILE* file, bool short_form = 0, char* last_db = 0); }; @@ -446,8 +457,12 @@ public: Intvar_log_event(const char* buf); ~Intvar_log_event() {} Log_event_type get_type_code() { return INTVAR_EVENT;} + const char* get_var_type_name(); int get_data_size() { return sizeof(type) + sizeof(val);} int write_data(IO_CACHE* file); +#ifndef MYSQL_CLIENT + void pack_info(String* packet); +#endif void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -491,6 +506,12 @@ public: int write_data(IO_CACHE* file); void print(FILE* file, bool short_form = 0, char* last_db = 0); +#ifndef MYSQL_CLIENT + void pack_info(String* packet); +#endif }; #endif + + + diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 6f423f879f8..efa17cf98c3 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -211,3 +211,5 @@ "Update locks cannot be acquired during a READ UNCOMMITTED transaction", "Error connecting to master: %-.128s", "Error running query on master: %-.128s", +"Error in SHOW BINLOG EVENTS: %-.128s", + diff --git a/sql/sql_lex.h b/sql/sql_lex.h index be4a7d1273f..a7b7f75f4a2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -55,7 +55,8 @@ enum enum_sql_command { SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS, SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA, SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, - SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, SQLCOM_UNION_SELECT + SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, SQLCOM_UNION_SELECT, + SQLCOM_SHOW_BINLOG_EVENTS }; enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8b11310e30e..0e3a1e4d91f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1179,6 +1179,13 @@ mysql_execute_command(void) res = show_slave_hosts(thd); break; } + case SQLCOM_SHOW_BINLOG_EVENTS: + { + if(check_access(thd, FILE_ACL, any_db)) + goto error; + res = show_binlog_events(thd); + break; + } case SQLCOM_BACKUP_TABLE: { if (check_db_used(thd,tables) || diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index ea777402e90..435319fe6e0 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -381,7 +381,8 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) if (pos < 4) { - errmsg = "Client requested master to start repliction from impossible position.\n"; + errmsg = "Client requested master to start repliction from \ +impossible position"; goto err; } @@ -826,6 +827,105 @@ void reset_master() } + +int show_binlog_events(THD* thd) +{ + DBUG_ENTER("show_binlog_events"); + List<Item> field_list; + const char* errmsg = 0; + IO_CACHE log; + File file = -1; + + Log_event::init_show_field_list(&field_list); + if (send_fields(thd, field_list, 1)) + DBUG_RETURN(-1); + + if (mysql_bin_log.is_open()) + { + LOG_INFO linfo; + char search_file_name[FN_REFLEN]; + LEX_MASTER_INFO* lex_mi = &thd->lex.mi; + uint event_count, limit_start, limit_end; + const char* log_file_name = lex_mi->log_file_name; + Log_event* ev; + ulong pos = (ulong) lex_mi->pos; + + limit_start = thd->lex.select->offset_limit; + limit_end = thd->lex.select->select_limit + limit_start; + + if (log_file_name) + mysql_bin_log.make_log_name(search_file_name, log_file_name); + else + search_file_name[0] = 0; + + linfo.index_file_offset = 0; + thd->current_linfo = &linfo; + + if (mysql_bin_log.find_first_log(&linfo, search_file_name)) + { + errmsg = "Could not find target log"; + goto err; + } + + if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) + goto err; + + if (pos < 4) + { + errmsg = "Invalid log position"; + goto err; + } + + pthread_mutex_lock(mysql_bin_log.get_log_lock()); + + my_b_seek(&log, pos); + + for (event_count = 0; + (ev = Log_event::read_log_event(&log, 0));) + { + if (event_count >= limit_start && + ev->net_send(thd, linfo.log_file_name, pos)) + { + errmsg = "Net error"; + delete ev; + pthread_mutex_unlock(mysql_bin_log.get_log_lock()); + goto err; + } + + pos = my_b_tell(&log); + delete ev; + + if (++event_count >= limit_end) + break; + } + + if (event_count < limit_end && log.error) + { + errmsg = "Wrong offset or I/O error"; + goto err; + } + + pthread_mutex_unlock(mysql_bin_log.get_log_lock()); + } + +err: + if (file >= 0) + { + end_io_cache(&log); + (void) my_close(file, MYF(MY_WME)); + } + + if (errmsg) + { + net_printf(&thd->net, ER_SHOW_BINLOG_EVENTS, errmsg); + DBUG_RETURN(1); + } + + send_eof(&thd->net); + DBUG_RETURN(0); +} + + int show_slave_hosts(THD* thd) { DBUG_ENTER("show_slave_hosts"); diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 281230071f1..a3ba11bdfdb 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -29,6 +29,7 @@ int load_master_data(THD* thd); int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi); int change_master(THD* thd); int show_slave_hosts(THD* thd); +int show_binlog_events(THD* thd); void reset_slave(); void reset_master(); void init_slave_list(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5483945ce36..8877d7eb08c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -130,6 +130,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token LOAD %token LOCK_SYM %token UNLOCK_SYM +%token BINLOG_SYM +%token EVENTS_SYM %token ACTION %token AGGREGATE_SYM @@ -466,12 +468,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); opt_escape %type <string> - text_string + text_string %type <num> type int_type real_type order_dir opt_field_spec set_option lock_option udf_type if_exists opt_local opt_table_options table_options - table_option opt_if_not_exists + table_option opt_if_not_exists %type <ulong_num> ULONG_NUM raid_types @@ -2406,6 +2408,10 @@ show_param: { Lex->sql_command = SQLCOM_SHOW_SLAVE_HOSTS; } + | BINLOG_SYM EVENTS_SYM binlog_in binlog_from limit_clause + { + Lex->sql_command = SQLCOM_SHOW_BINLOG_EVENTS; + } | keys_or_index FROM table_ident opt_db { Lex->sql_command= SQLCOM_SHOW_KEYS; @@ -2456,6 +2462,15 @@ opt_full: /* empty */ { Lex->verbose=0; } | FULL { Lex->verbose=1; } +binlog_in: + /* empty */ { Lex->mi.log_file_name = 0; } + | IN_SYM TEXT_STRING { Lex->mi.log_file_name = $2.str; } + +binlog_from: + /* empty */ { Lex->mi.pos = 4; /* skip magic number */ } + | FROM ULONGLONG_NUM { Lex->mi.pos = $2; } + + /* A Oracle compatible synonym for show */ describe: describe_command table_ident |