The world's most popular open source database
00001 /* Copyright (C) 2001-2004 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /* 00018 00019 TODO: print the catalog (some USE catalog.db ????). 00020 00021 Standalone program to read a MySQL binary log (or relay log); 00022 can read files produced by 3.23, 4.x, 5.0 servers. 00023 00024 Can read binlogs from 3.23/4.x/5.0 and relay logs from 4.x/5.0. 00025 Should be able to read any file of these categories, even with 00026 --start-position. 00027 An important fact: the Format_desc event of the log is at most the 3rd event 00028 of the log; if it is the 3rd then there is this combination: 00029 Format_desc_of_slave, Rotate_of_master, Format_desc_of_master. 00030 */ 00031 00032 #define MYSQL_CLIENT 00033 #undef MYSQL_SERVER 00034 #include "client_priv.h" 00035 #include <my_time.h> 00036 /* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */ 00037 #include "mysql_priv.h" 00038 #include "log_event.h" 00039 #include "sql_common.h" 00040 00041 #define BIN_LOG_HEADER_SIZE 4 00042 #define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4) 00043 00044 00045 #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES) 00046 00047 char server_version[SERVER_VERSION_LENGTH]; 00048 ulong server_id = 0; 00049 00050 // needed by net_serv.c 00051 ulong bytes_sent = 0L, bytes_received = 0L; 00052 ulong mysqld_net_retry_count = 10L; 00053 ulong open_files_limit; 00054 uint test_flags = 0; 00055 static uint opt_protocol= 0; 00056 static FILE *result_file; 00057 00058 #ifndef DBUG_OFF 00059 static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace"; 00060 #endif 00061 static const char *load_default_groups[]= { "mysqlbinlog","client",0 }; 00062 00063 void sql_print_error(const char *format, ...); 00064 00065 static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0; 00066 static bool opt_hexdump= 0; 00067 static bool opt_base64_output= 0; 00068 static const char* database= 0; 00069 static my_bool force_opt= 0, short_form= 0, remote_opt= 0; 00070 static ulonglong offset = 0; 00071 static const char* host = 0; 00072 static int port= 0; 00073 static const char* sock= 0; 00074 static const char* user = 0; 00075 static char* pass = 0; 00076 static char *charset= 0; 00077 00078 static ulonglong start_position, stop_position; 00079 #define start_position_mot ((my_off_t)start_position) 00080 #define stop_position_mot ((my_off_t)stop_position) 00081 00082 static char *start_datetime_str, *stop_datetime_str; 00083 static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX; 00084 static ulonglong rec_count= 0; 00085 static short binlog_flags = 0; 00086 static MYSQL* mysql = NULL; 00087 static const char* dirname_for_local_load= 0; 00088 static bool stop_passed= 0; 00089 00090 /* 00091 check_header() will set the pointer below. 00092 Why do we need here a pointer on an event instead of an event ? 00093 This is because the event will be created (alloced) in read_log_event() 00094 (which returns a pointer) in check_header(). 00095 */ 00096 Format_description_log_event* description_event; 00097 00098 static int dump_local_log_entries(const char* logname); 00099 static int dump_remote_log_entries(const char* logname); 00100 static int dump_log_entries(const char* logname); 00101 static int dump_remote_file(NET* net, const char* fname); 00102 static void die(const char* fmt, ...); 00103 static MYSQL* safe_connect(); 00104 00105 00106 class Load_log_processor 00107 { 00108 char target_dir_name[FN_REFLEN]; 00109 int target_dir_name_len; 00110 00111 /* 00112 When we see first event corresponding to some LOAD DATA statement in 00113 binlog, we create temporary file to store data to be loaded. 00114 We add name of this file to file_names array using its file_id as index. 00115 If we have Create_file event (i.e. we have binary log in pre-5.0.3 00116 format) we also store save event object to be able which is needed to 00117 emit LOAD DATA statement when we will meet Exec_load_data event. 00118 If we have Begin_load_query event we simply store 0 in 00119 File_name_record::event field. 00120 */ 00121 struct File_name_record 00122 { 00123 char *fname; 00124 Create_file_log_event *event; 00125 }; 00126 DYNAMIC_ARRAY file_names; 00127 00128 /* 00129 Looking for new uniquie filename that doesn't exist yet by 00130 adding postfix -%x 00131 00132 SYNOPSIS 00133 create_unique_file() 00134 00135 filename buffer for filename 00136 file_name_end tail of buffer that should be changed 00137 should point to a memory enough to printf("-%x",..) 00138 00139 RETURN VALUES 00140 values less than 0 - can't find new filename 00141 values great or equal 0 - created file with found filename 00142 */ 00143 File create_unique_file(char *filename, char *file_name_end) 00144 { 00145 File res; 00146 /* If we have to try more than 1000 times, something is seriously wrong */ 00147 for (uint version= 0; version<1000; version++) 00148 { 00149 sprintf(file_name_end,"-%x",version); 00150 if ((res= my_create(filename,0, 00151 O_CREAT|O_EXCL|O_BINARY|O_WRONLY,MYF(0)))!=-1) 00152 return res; 00153 } 00154 return -1; 00155 } 00156 00157 public: 00158 Load_log_processor() {} 00159 ~Load_log_processor() 00160 { 00161 destroy(); 00162 delete_dynamic(&file_names); 00163 } 00164 00165 int init() 00166 { 00167 return init_dynamic_array(&file_names, sizeof(File_name_record), 00168 100,100 CALLER_INFO); 00169 } 00170 00171 void init_by_dir_name(const char *dir) 00172 { 00173 target_dir_name_len= (convert_dirname(target_dir_name, dir, NullS) - 00174 target_dir_name); 00175 } 00176 void init_by_cur_dir() 00177 { 00178 if (my_getwd(target_dir_name,sizeof(target_dir_name),MYF(MY_WME))) 00179 exit(1); 00180 target_dir_name_len= strlen(target_dir_name); 00181 } 00182 void destroy() 00183 { 00184 File_name_record *ptr= (File_name_record *)file_names.buffer; 00185 File_name_record *end= ptr + file_names.elements; 00186 for (; ptr<end; ptr++) 00187 { 00188 if (ptr->fname) 00189 { 00190 my_free(ptr->fname, MYF(MY_WME)); 00191 delete ptr->event; 00192 bzero((char *)ptr, sizeof(File_name_record)); 00193 } 00194 } 00195 } 00196 00197 /* 00198 Obtain Create_file event for LOAD DATA statement by its file_id. 00199 00200 SYNOPSIS 00201 grab_event() 00202 file_id - file_id identifiying LOAD DATA statement 00203 00204 DESCRIPTION 00205 Checks whenever we have already seen Create_file event for this file_id. 00206 If yes then returns pointer to it and removes it from array describing 00207 active temporary files. Since this moment caller is responsible for 00208 freeing memory occupied by this event and associated file name. 00209 00210 RETURN VALUES 00211 Pointer to Create_file event or 0 if there was no such event 00212 with this file_id. 00213 */ 00214 Create_file_log_event *grab_event(uint file_id) 00215 { 00216 File_name_record *ptr; 00217 Create_file_log_event *res; 00218 00219 if (file_id >= file_names.elements) 00220 return 0; 00221 ptr= dynamic_element(&file_names, file_id, File_name_record*); 00222 if ((res= ptr->event)) 00223 bzero((char *)ptr, sizeof(File_name_record)); 00224 return res; 00225 } 00226 00227 /* 00228 Obtain file name of temporary file for LOAD DATA statement by its file_id. 00229 00230 SYNOPSIS 00231 grab_fname() 00232 file_id - file_id identifiying LOAD DATA statement 00233 00234 DESCRIPTION 00235 Checks whenever we have already seen Begin_load_query event for this 00236 file_id. If yes then returns file name of corresponding temporary file. 00237 Removes record about this file from the array of active temporary files. 00238 Since this moment caller is responsible for freeing memory occupied by 00239 this name. 00240 00241 RETURN VALUES 00242 String with name of temporary file or 0 if we have not seen Begin_load_query 00243 event with this file_id. 00244 */ 00245 char *grab_fname(uint file_id) 00246 { 00247 File_name_record *ptr; 00248 char *res= 0; 00249 00250 if (file_id >= file_names.elements) 00251 return 0; 00252 ptr= dynamic_element(&file_names, file_id, File_name_record*); 00253 if (!ptr->event) 00254 { 00255 res= ptr->fname; 00256 bzero((char *)ptr, sizeof(File_name_record)); 00257 } 00258 return res; 00259 } 00260 int process(Create_file_log_event *ce); 00261 int process(Begin_load_query_log_event *ce); 00262 int process(Append_block_log_event *ae); 00263 File prepare_new_file_for_old_format(Load_log_event *le, char *filename); 00264 int load_old_format_file(NET* net, const char *server_fname, 00265 uint server_fname_len, File file); 00266 int process_first_event(const char *bname, uint blen, const char *block, 00267 uint block_len, uint file_id, 00268 Create_file_log_event *ce); 00269 }; 00270 00271 00272 00273 File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, 00274 char *filename) 00275 { 00276 uint len; 00277 char *tail; 00278 File file; 00279 00280 fn_format(filename, le->fname, target_dir_name, "", 1); 00281 len= strlen(filename); 00282 tail= filename + len; 00283 00284 if ((file= create_unique_file(filename,tail)) < 0) 00285 { 00286 sql_print_error("Could not construct local filename %s",filename); 00287 return -1; 00288 } 00289 00290 le->set_fname_outside_temp_buf(filename,len+strlen(tail)); 00291 00292 return file; 00293 } 00294 00295 00296 int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, 00297 uint server_fname_len, File file) 00298 { 00299 char buf[FN_REFLEN+1]; 00300 buf[0] = 0; 00301 memcpy(buf + 1, server_fname, server_fname_len + 1); 00302 if (my_net_write(net, buf, server_fname_len +2) || net_flush(net)) 00303 { 00304 sql_print_error("Failed requesting the remote dump of %s", server_fname); 00305 return -1; 00306 } 00307 00308 for (;;) 00309 { 00310 ulong packet_len = my_net_read(net); 00311 if (packet_len == 0) 00312 { 00313 if (my_net_write(net, "", 0) || net_flush(net)) 00314 { 00315 sql_print_error("Failed sending the ack packet"); 00316 return -1; 00317 } 00318 /* 00319 we just need to send something, as the server will read but 00320 not examine the packet - this is because mysql_load() sends 00321 an OK when it is done 00322 */ 00323 break; 00324 } 00325 else if (packet_len == packet_error) 00326 { 00327 sql_print_error("Failed reading a packet during the dump of %s ", 00328 server_fname); 00329 return -1; 00330 } 00331 00332 if (packet_len > UINT_MAX) 00333 { 00334 sql_print_error("Illegal length of packet read from net"); 00335 return -1; 00336 } 00337 if (my_write(file, (byte*) net->read_pos, 00338 (uint) packet_len, MYF(MY_WME|MY_NABP))) 00339 return -1; 00340 } 00341 00342 return 0; 00343 } 00344 00345 00346 /* 00347 Process first event in the sequence of events representing LOAD DATA 00348 statement. 00349 00350 SYNOPSIS 00351 process_first_event() 00352 bname - base name for temporary file to be created 00353 blen - base name length 00354 block - first block of data to be loaded 00355 block_len - first block length 00356 file_id - identifies LOAD DATA statement 00357 ce - pointer to Create_file event object if we are processing 00358 this type of event. 00359 00360 DESCRIPTION 00361 Creates temporary file to be used in LOAD DATA and writes first block of 00362 data to it. Registers its file name (and optional Create_file event) 00363 in the array of active temporary files. 00364 00365 RETURN VALUES 00366 0 - success 00367 non-0 - error 00368 */ 00369 00370 int Load_log_processor::process_first_event(const char *bname, uint blen, 00371 const char *block, uint block_len, 00372 uint file_id, 00373 Create_file_log_event *ce) 00374 { 00375 uint full_len= target_dir_name_len + blen + 9 + 9 + 1; 00376 int error= 0; 00377 char *fname, *ptr; 00378 File file; 00379 File_name_record rec; 00380 DBUG_ENTER("Load_log_processor::process_first_event"); 00381 00382 if (!(fname= my_malloc(full_len,MYF(MY_WME)))) 00383 DBUG_RETURN(-1); 00384 00385 memcpy(fname, target_dir_name, target_dir_name_len); 00386 ptr= fname + target_dir_name_len; 00387 memcpy(ptr,bname,blen); 00388 ptr+= blen; 00389 ptr+= my_sprintf(ptr, (ptr, "-%x", file_id)); 00390 00391 if ((file= create_unique_file(fname,ptr)) < 0) 00392 { 00393 sql_print_error("Could not construct local filename %s%s", 00394 target_dir_name,bname); 00395 DBUG_RETURN(-1); 00396 } 00397 00398 rec.fname= fname; 00399 rec.event= ce; 00400 00401 if (set_dynamic(&file_names, (gptr)&rec, file_id)) 00402 { 00403 sql_print_error("Could not construct local filename %s%s", 00404 target_dir_name, bname); 00405 DBUG_RETURN(-1); 00406 } 00407 00408 if (ce) 00409 ce->set_fname_outside_temp_buf(fname, strlen(fname)); 00410 00411 if (my_write(file, (byte*)block, block_len, MYF(MY_WME|MY_NABP))) 00412 error= -1; 00413 if (my_close(file, MYF(MY_WME))) 00414 error= -1; 00415 DBUG_RETURN(error); 00416 } 00417 00418 00419 int Load_log_processor::process(Create_file_log_event *ce) 00420 { 00421 const char *bname= ce->fname + dirname_length(ce->fname); 00422 uint blen= ce->fname_len - (bname-ce->fname); 00423 00424 return process_first_event(bname, blen, ce->block, ce->block_len, 00425 ce->file_id, ce); 00426 } 00427 00428 00429 int Load_log_processor::process(Begin_load_query_log_event *blqe) 00430 { 00431 return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len, 00432 blqe->file_id, 0); 00433 } 00434 00435 00436 int Load_log_processor::process(Append_block_log_event *ae) 00437 { 00438 DBUG_ENTER("Load_log_processor::process"); 00439 const char* fname= ((ae->file_id < file_names.elements) ? 00440 dynamic_element(&file_names, ae->file_id, 00441 File_name_record*)->fname : 0); 00442 00443 if (fname) 00444 { 00445 File file; 00446 int error= 0; 00447 if (((file= my_open(fname, 00448 O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0)) 00449 DBUG_RETURN(-1); 00450 if (my_write(file,(byte*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP))) 00451 error= -1; 00452 if (my_close(file,MYF(MY_WME))) 00453 error= -1; 00454 DBUG_RETURN(error); 00455 } 00456 00457 /* 00458 There is no Create_file event (a bad binlog or a big 00459 --start-position). Assuming it's a big --start-position, we just do 00460 nothing and print a warning. 00461 */ 00462 fprintf(stderr,"Warning: ignoring Append_block as there is no \ 00463 Create_file event for file_id: %u\n",ae->file_id); 00464 DBUG_RETURN(-1); 00465 } 00466 00467 00468 Load_log_processor load_processor; 00469 00470 00471 static bool check_database(const char *log_dbname) 00472 { 00473 return one_database && 00474 (log_dbname != NULL) && 00475 strcmp(log_dbname, database); 00476 } 00477 00478 00479 /* 00480 Process an event 00481 00482 SYNOPSIS 00483 process_event() 00484 00485 RETURN 00486 0 ok and continue 00487 1 error and terminate 00488 -1 ok and terminate 00489 00490 TODO 00491 This function returns 0 even in some error cases. This should be changed. 00492 */ 00493 00494 00495 00496 int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, 00497 my_off_t pos) 00498 { 00499 char ll_buff[21]; 00500 Log_event_type ev_type= ev->get_type_code(); 00501 DBUG_ENTER("process_event"); 00502 print_event_info->short_form= short_form; 00503 00504 /* 00505 Format events are not concerned by --offset and such, we always need to 00506 read them to be able to process the wanted events. 00507 */ 00508 if ((rec_count >= offset) && 00509 ((my_time_t)(ev->when) >= start_datetime) || 00510 (ev_type == FORMAT_DESCRIPTION_EVENT)) 00511 { 00512 if (ev_type != FORMAT_DESCRIPTION_EVENT) 00513 { 00514 /* 00515 We have found an event after start_datetime, from now on print 00516 everything (in case the binlog has timestamps increasing and 00517 decreasing, we do this to avoid cutting the middle). 00518 */ 00519 start_datetime= 0; 00520 offset= 0; // print everything and protect against cycling rec_count 00521 } 00522 if (server_id && (server_id != ev->server_id)) { 00523 DBUG_RETURN(0); 00524 } 00525 if (((my_time_t)(ev->when) >= stop_datetime) 00526 || (pos >= stop_position_mot)) 00527 { 00528 stop_passed= 1; // skip all next binlogs 00529 DBUG_RETURN(-1); 00530 } 00531 if (!short_form) 00532 fprintf(result_file, "# at %s\n",llstr(pos,ll_buff)); 00533 00534 if (!opt_hexdump) 00535 print_event_info->hexdump_from= 0; /* Disabled */ 00536 else 00537 print_event_info->hexdump_from= pos; 00538 00539 print_event_info->base64_output= opt_base64_output; 00540 00541 switch (ev_type) { 00542 case QUERY_EVENT: 00543 if (check_database(((Query_log_event*)ev)->db)) 00544 goto end; 00545 if (opt_base64_output) 00546 { 00547 ev->print_header(result_file, print_event_info); 00548 ev->print_base64(result_file, print_event_info); 00549 } 00550 else 00551 ev->print(result_file, print_event_info); 00552 break; 00553 case CREATE_FILE_EVENT: 00554 { 00555 Create_file_log_event* ce= (Create_file_log_event*)ev; 00556 /* 00557 We test if this event has to be ignored. If yes, we don't save 00558 this event; this will have the good side-effect of ignoring all 00559 related Append_block and Exec_load. 00560 Note that Load event from 3.23 is not tested. 00561 */ 00562 if (check_database(ce->db)) 00563 goto end; // Next event 00564 /* 00565 We print the event, but with a leading '#': this is just to inform 00566 the user of the original command; the command we want to execute 00567 will be a derivation of this original command (we will change the 00568 filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT' 00569 below. 00570 */ 00571 if (opt_base64_output) 00572 { 00573 ce->print_header(result_file, print_event_info); 00574 ce->print_base64(result_file, print_event_info); 00575 } 00576 else 00577 ce->print(result_file, print_event_info, TRUE); 00578 00579 // If this binlog is not 3.23 ; why this test?? 00580 if (description_event->binlog_version >= 3) 00581 { 00582 if (load_processor.process(ce)) 00583 break; // Error 00584 ev= 0; 00585 } 00586 break; 00587 } 00588 case APPEND_BLOCK_EVENT: 00589 ev->print(result_file, print_event_info); 00590 if (load_processor.process((Append_block_log_event*) ev)) 00591 break; // Error 00592 break; 00593 case EXEC_LOAD_EVENT: 00594 { 00595 ev->print(result_file, print_event_info); 00596 Execute_load_log_event *exv= (Execute_load_log_event*)ev; 00597 Create_file_log_event *ce= load_processor.grab_event(exv->file_id); 00598 /* 00599 if ce is 0, it probably means that we have not seen the Create_file 00600 event (a bad binlog, or most probably --start-position is after the 00601 Create_file event). Print a warning comment. 00602 */ 00603 if (ce) 00604 { 00605 ce->print(result_file, print_event_info, TRUE); 00606 my_free((char*)ce->fname,MYF(MY_WME)); 00607 delete ce; 00608 } 00609 else 00610 fprintf(stderr,"Warning: ignoring Exec_load as there is no \ 00611 Create_file event for file_id: %u\n",exv->file_id); 00612 break; 00613 } 00614 case FORMAT_DESCRIPTION_EVENT: 00615 delete description_event; 00616 description_event= (Format_description_log_event*) ev; 00617 print_event_info->common_header_len= description_event->common_header_len; 00618 ev->print(result_file, print_event_info); 00619 /* 00620 We don't want this event to be deleted now, so let's hide it (I 00621 (Guilhem) should later see if this triggers a non-serious Valgrind 00622 error). Not serious error, because we will free description_event 00623 later. 00624 */ 00625 ev= 0; 00626 break; 00627 case BEGIN_LOAD_QUERY_EVENT: 00628 ev->print(result_file, print_event_info); 00629 load_processor.process((Begin_load_query_log_event*) ev); 00630 break; 00631 case EXECUTE_LOAD_QUERY_EVENT: 00632 { 00633 Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev; 00634 char *fname= load_processor.grab_fname(exlq->file_id); 00635 00636 if (check_database(exlq->db)) 00637 { 00638 if (fname) 00639 my_free(fname, MYF(MY_WME)); 00640 goto end; 00641 } 00642 00643 if (fname) 00644 { 00645 exlq->print(result_file, print_event_info, fname); 00646 my_free(fname, MYF(MY_WME)); 00647 } 00648 else 00649 fprintf(stderr,"Warning: ignoring Execute_load_query as there is no \ 00650 Begin_load_query event for file_id: %u\n", exlq->file_id); 00651 break; 00652 } 00653 default: 00654 ev->print(result_file, print_event_info); 00655 } 00656 } 00657 00658 end: 00659 rec_count++; 00660 if (ev) 00661 delete ev; 00662 DBUG_RETURN(0); 00663 } 00664 00665 00666 static struct my_option my_long_options[] = 00667 { 00668 {"help", '?', "Display this help and exit.", 00669 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00670 #ifdef __NETWARE__ 00671 {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 00672 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00673 #endif 00674 {"base64-output", OPT_BASE64_OUTPUT, 00675 "Print all binlog entries using base64 encoding. " 00676 "This is for debugging only. Logs produced using this option " 00677 "should not be applied on production systems.", 00678 (gptr*) &opt_base64_output, (gptr*) &opt_base64_output, 0, GET_BOOL, 00679 NO_ARG, 0, 0, 0, 0, 0, 0}, 00680 /* 00681 mysqlbinlog needs charsets knowledge, to be able to convert a charset 00682 number found in binlog to a charset name (to be able to print things 00683 like this: 00684 SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`; 00685 */ 00686 {"character-sets-dir", OPT_CHARSETS_DIR, 00687 "Directory where character sets are.", (gptr*) &charsets_dir, 00688 (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00689 {"database", 'd', "List entries for just this database (local log only).", 00690 (gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, 00691 0, 0, 0, 0, 0, 0}, 00692 #ifndef DBUG_OFF 00693 {"debug", '#', "Output debug log.", (gptr*) &default_dbug_option, 00694 (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00695 #endif 00696 {"disable-log-bin", 'D', "Disable binary log. This is useful, if you " 00697 "enabled --to-last-log and are sending the output to the same MySQL server. " 00698 "This way you could avoid an endless loop. You would also like to use it " 00699 "when restoring after a crash to avoid duplication of the statements you " 00700 "already have. NOTE: you will need a SUPER privilege to use this option.", 00701 (gptr*) &disable_log_bin, (gptr*) &disable_log_bin, 0, GET_BOOL, 00702 NO_ARG, 0, 0, 0, 0, 0, 0}, 00703 {"force-read", 'f', "Force reading unknown binlog events.", 00704 (gptr*) &force_opt, (gptr*) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 00705 0, 0}, 00706 {"hexdump", 'H', "Augment output with hexadecimal and ASCII event dump.", 00707 (gptr*) &opt_hexdump, (gptr*) &opt_hexdump, 0, GET_BOOL, NO_ARG, 00708 0, 0, 0, 0, 0, 0}, 00709 {"host", 'h', "Get the binlog from server.", (gptr*) &host, (gptr*) &host, 00710 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00711 {"local-load", 'l', "Prepare local temporary files for LOAD DATA INFILE in the specified directory.", 00712 (gptr*) &dirname_for_local_load, (gptr*) &dirname_for_local_load, 0, 00713 GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00714 {"offset", 'o', "Skip the first N entries.", (gptr*) &offset, (gptr*) &offset, 00715 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00716 {"password", 'p', "Password to connect to remote server.", 00717 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00718 {"port", 'P', "Use port to connect to the remote server.", 00719 (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 00720 0, 0, 0}, 00721 {"position", 'j', "Deprecated. Use --start-position instead.", 00722 (gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL, 00723 REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, 00724 /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ 00725 (ulonglong)(~(uint32)0), 0, 0, 0}, 00726 {"protocol", OPT_MYSQL_PROTOCOL, 00727 "The protocol of connection (tcp,socket,pipe,memory).", 00728 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00729 {"read-from-remote-server", 'R', "Read binary logs from a MySQL server", 00730 (gptr*) &remote_opt, (gptr*) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 00731 0, 0}, 00732 {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR, 00733 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00734 {"server-id", OPT_SERVER_ID, 00735 "Extract only binlog entries created by the server having the given id.", 00736 (gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG, 00737 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00738 {"set-charset", OPT_SET_CHARSET, 00739 "Add 'SET NAMES character_set' to the output.", (gptr*) &charset, 00740 (gptr*) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00741 {"short-form", 's', "Just show the queries, no extra info.", 00742 (gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 00743 0, 0}, 00744 {"socket", 'S', "Socket file to use for connection.", 00745 (gptr*) &sock, (gptr*) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 00746 0, 0}, 00747 {"start-datetime", OPT_START_DATETIME, 00748 "Start reading the binlog at first event having a datetime equal or " 00749 "posterior to the argument; the argument must be a date and time " 00750 "in the local time zone, in any format accepted by the MySQL server " 00751 "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 " 00752 "(you should probably use quotes for your shell to set it properly).", 00753 (gptr*) &start_datetime_str, (gptr*) &start_datetime_str, 00754 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00755 {"start-position", OPT_START_POSITION, 00756 "Start reading the binlog at position N. Applies to the first binlog " 00757 "passed on the command line.", 00758 (gptr*) &start_position, (gptr*) &start_position, 0, GET_ULL, 00759 REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, 00760 /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ 00761 (ulonglong)(~(uint32)0), 0, 0, 0}, 00762 {"stop-datetime", OPT_STOP_DATETIME, 00763 "Stop reading the binlog at first event having a datetime equal or " 00764 "posterior to the argument; the argument must be a date and time " 00765 "in the local time zone, in any format accepted by the MySQL server " 00766 "for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 " 00767 "(you should probably use quotes for your shell to set it properly).", 00768 (gptr*) &stop_datetime_str, (gptr*) &stop_datetime_str, 00769 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00770 {"stop-position", OPT_STOP_POSITION, 00771 "Stop reading the binlog at position N. Applies to the last binlog " 00772 "passed on the command line.", 00773 (gptr*) &stop_position, (gptr*) &stop_position, 0, GET_ULL, 00774 REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, 00775 (ulonglong)(~(my_off_t)0), 0, 0, 0}, 00776 {"to-last-log", 't', "Requires -R. Will not stop at the end of the \ 00777 requested binlog but rather continue printing until the end of the last \ 00778 binlog of the MySQL server. If you send the output to the same MySQL server, \ 00779 that may lead to an endless loop.", 00780 (gptr*) &to_last_remote_log, (gptr*) &to_last_remote_log, 0, GET_BOOL, 00781 NO_ARG, 0, 0, 0, 0, 0, 0}, 00782 {"user", 'u', "Connect to the remote server as username.", 00783 (gptr*) &user, (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 00784 0, 0}, 00785 {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 00786 0, 0, 0, 0, 0}, 00787 {"open_files_limit", OPT_OPEN_FILES_LIMIT, 00788 "Used to reserve file descriptors for usage by this program", 00789 (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, 00790 REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, 00791 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} 00792 }; 00793 00794 00795 void sql_print_error(const char *format,...) 00796 { 00797 va_list args; 00798 va_start(args, format); 00799 fprintf(stderr, "ERROR: "); 00800 vfprintf(stderr, format, args); 00801 fprintf(stderr, "\n"); 00802 va_end(args); 00803 } 00804 00805 static void cleanup() 00806 { 00807 my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); 00808 my_free((char*) database, MYF(MY_ALLOW_ZERO_PTR)); 00809 my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR)); 00810 my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR)); 00811 my_free((char*) dirname_

