mysqlbinlog.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16. #define MYSQL_CLIENT
  17. #undef MYSQL_SERVER
  18. #include <global.h>
  19. #include <m_string.h>
  20. #include <my_sys.h>
  21. #include <getopt.h>
  22. #include <thr_alarm.h>
  23. #define MYSQL_SERVER // We want the C++ version of net
  24. #include <mysql.h>
  25. #include "log_event.h"
  26. #include "mini_client.h"
  27. #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
  28. char server_version[SERVER_VERSION_LENGTH];
  29. uint32 server_id = 0;
  30. // needed by net_serv.c
  31. ulong bytes_sent = 0L, bytes_received = 0L;
  32. ulong mysqld_net_retry_count = 10L;
  33. ulong net_read_timeout=  NET_READ_TIMEOUT;
  34. ulong net_write_timeout= NET_WRITE_TIMEOUT;
  35. uint test_flags = 0; 
  36. #ifndef DBUG_OFF
  37. static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
  38. #endif
  39. static struct option long_options[] =
  40. {
  41. #ifndef DBUG_OFF
  42.   {"debug",  optional_argument,  0, '#'},
  43. #endif
  44.   {"help",  no_argument,  0, '?'},
  45.   {"host",  required_argument, 0, 'h'},
  46.   {"offset",  required_argument, 0, 'o'},
  47.   {"password", required_argument, 0, 'p'},
  48.   {"port",  required_argument, 0, 'P'},
  49.   {"position", required_argument, 0, 'j'},
  50.   {"short-form", no_argument, 0, 's'},
  51.   {"table",  required_argument,  0, 't'},
  52.   {"user", required_argument, 0, 'u'},
  53.   {"version",  no_argument,  0, 'V'},
  54. };
  55. void sql_print_error(const char *format,...);
  56. static bool short_form = 0;
  57. static ulonglong offset = 0;
  58. static const char* host = "localhost";
  59. static int port = MYSQL_PORT;
  60. static const char* user = "test";
  61. static const char* pass = "";
  62. static ulonglong position = 0;
  63. static bool use_remote = 0;
  64. static short binlog_flags = 0; 
  65. static MYSQL* mysql = NULL;
  66. static const char* table = 0;
  67. static void dump_local_log_entries(const char* logname);
  68. static void dump_remote_log_entries(const char* logname);
  69. static void dump_log_entries(const char* logname);
  70. static void dump_remote_file(NET* net, const char* fname);
  71. static void dump_remote_table(NET* net, const char* db, const char* table);
  72. static void die(const char* fmt, ...);
  73. static MYSQL* safe_connect();
  74. void sql_print_error(const char *format,...)
  75. {
  76.   va_list args;
  77.   va_start(args, format);
  78.   fprintf(stderr, "ERROR: ");
  79.   vfprintf(stderr, format, args);
  80.   fprintf(stderr, "n");
  81.   va_end(args);
  82. }
  83. static void die(const char* fmt, ...)
  84. {
  85.   va_list args;
  86.   va_start(args, fmt);
  87.   fprintf(stderr, "ERROR: ");
  88.   vfprintf(stderr, fmt, args);
  89.   fprintf(stderr, "n");
  90.   va_end(args);
  91.   exit(1);
  92. }
  93. static void print_version()
  94. {
  95.   printf("%s  Ver 1.2 for %s at %sn",my_progname,SYSTEM_TYPE, MACHINE_TYPE);
  96. }
  97. static void usage()
  98. {
  99.   print_version();
  100.   puts("By Sasha, for your professional usen
  101. This software comes with NO WARRANTY: see the file PUBLIC for detailsn");
  102.   printf("
  103. Dumps a MySQL binary log in a format usable for viewing or for pipeing ton
  104. the mysql command line clientnn");
  105.   printf("Usage: %s [options] log-filesn",my_progname);
  106.   puts("Options:");
  107. #ifndef DBUG_OFF
  108.   printf("-#, --debug[=...]       Output debug log.  (%s)n",
  109.  default_dbug_option);
  110. #endif
  111.   printf("
  112. -?, --help Display this help and exitn
  113. -s, --short-form Just show the queries, no extra infon
  114. -o, --offset=N Skip the first N entriesn
  115. -h, --host=server Get the binlog from servern
  116. -P, --port=port         Use port to connect to the remove servern
  117. -u, --user=username     Connect to the remove server as usernamen
  118. -p, --password=password Password to connect to remote servern
  119. -j, --position=N Start reading the binlog at position Nn
  120. -t, --table=name        Get raw table dump using COM_TABLE_DUMBn
  121. -V, --version Print version and exit.n
  122. ");
  123. }
  124. static void dump_remote_file(NET* net, const char* fname)
  125. {
  126.   char buf[FN_REFLEN+1];
  127.   uint len = (uint) strlen(fname);
  128.   buf[0] = 0;
  129.   memcpy(buf + 1, fname, len + 1);
  130.   if(my_net_write(net, buf, len +2) || net_flush(net))
  131.     die("Failed  requesting the remote dump of %s", fname);
  132.   for(;;)
  133.     {
  134.       uint packet_len = my_net_read(net);
  135.       if(packet_len == 0)
  136. {
  137.   if(my_net_write(net, "", 0) || net_flush(net))
  138.     die("Failed sending the ack packet");
  139.   // we just need to send something, as the server will read but
  140.   // not examine the packet - this is because mysql_load() sends an OK when it is done
  141.   break;
  142. }
  143.       else if(packet_len == packet_error)
  144. die("Failed reading a packet during the dump of %s ", fname);
  145.       if(!short_form)
  146. (void)my_fwrite(stdout, (byte*) net->read_pos, packet_len, MYF(0));
  147.     }
  148.   fflush(stdout);
  149. }
  150. static int parse_args(int *argc, char*** argv)
  151. {
  152.   int c, opt_index = 0;
  153.   while((c = getopt_long(*argc, *argv, "so:#::h:j:u:p:P:t:?V", long_options,
  154.  &opt_index)) != EOF)
  155.   {
  156.     switch(c)
  157.     {
  158. #ifndef DBUG_OFF
  159.     case '#':
  160.       DBUG_PUSH(optarg ? optarg : default_dbug_option);
  161.       break;
  162. #endif
  163.     case 's':
  164.       short_form = 1;
  165.       break;
  166.     case 'o':
  167.       offset = strtoull(optarg,(char**) 0, 10);
  168.       break;
  169.     case 'j':
  170.       position = strtoull(optarg,(char**) 0, 10);
  171.       break;
  172.     case 'h':
  173.       use_remote = 1;
  174.       host = my_strdup(optarg, MYF(0));
  175.       break;
  176.       
  177.     case 'P':
  178.       use_remote = 1;
  179.       port = atoi(optarg);
  180.       break;
  181.       
  182.     case 'p':
  183.       use_remote = 1;
  184.       pass = my_strdup(optarg, MYF(0));
  185.       break;
  186.     case 'u':
  187.       use_remote = 1;
  188.       user = my_strdup(optarg, MYF(0));
  189.       break;
  190.     case 't':
  191.       table = my_strdup(optarg, MYF(0));
  192.       break;
  193.     case 'V':
  194.       print_version();
  195.       exit(0);
  196.     case '?':
  197.     default:
  198.       usage();
  199.       exit(0);
  200.     }
  201.   }
  202.   (*argc)-=optind;
  203.   (*argv)+=optind;
  204.   return 0;
  205. }
  206. static MYSQL* safe_connect()
  207. {
  208.   MYSQL *local_mysql = mc_mysql_init(NULL);
  209.   if(!local_mysql)
  210.     die("Failed on mc_mysql_init");
  211.   if(!mc_mysql_connect(local_mysql, host, user, pass, 0, port, 0, 0))
  212.     die("failed on connect: %s", mc_mysql_error(local_mysql));
  213.   return local_mysql;
  214. }
  215. static void dump_log_entries(const char* logname)
  216. {
  217.   if(use_remote)
  218.     dump_remote_log_entries(logname);
  219.   else
  220.     dump_local_log_entries(logname);  
  221. }
  222. static void dump_remote_table(NET* net, const char* db, const char* table)
  223. {
  224.   char buf[1024];
  225.   char * p = buf;
  226.   uint table_len = (uint) strlen(table);
  227.   uint db_len = (uint) strlen(db);
  228.   if(table_len + db_len > sizeof(buf) - 2)
  229.     die("Buffer overrun");
  230.   
  231.   *p++ = db_len;
  232.   memcpy(p, db, db_len);
  233.   p += db_len;
  234.   *p++ = table_len;
  235.   memcpy(p, table, table_len);
  236.   
  237.   if(mc_simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
  238.     die("Error sending the table dump command");
  239.   for(;;)
  240.     {
  241.       uint packet_len = my_net_read(net);
  242.       if(packet_len == 0) break; // end of file
  243.       if(packet_len == packet_error)
  244. die("Error reading packet in table dump");
  245.       my_fwrite(stdout, (byte*)net->read_pos, packet_len, MYF(MY_WME));
  246.       fflush(stdout);
  247.     }
  248. }
  249. static void dump_remote_log_entries(const char* logname)
  250. {
  251.   char buf[128];
  252.   uint len;
  253.   NET* net = &mysql->net;
  254.   if(!position) position = 4; // protect the innocent from spam
  255.   if(position < 4)
  256.     {
  257.       position = 4;
  258.       // warn the guity
  259.       fprintf(stderr,
  260.       "Warning: with the position so small you would hit the magic numbern
  261. Unfortunately, no sweepstakes today, adjusted position to 4n");
  262.     }
  263.   int4store(buf, position);
  264.   int2store(buf + 4, binlog_flags);
  265.   len = (uint) strlen(logname);
  266.   int4store(buf + 6, 0);
  267.   memcpy(buf + 10, logname,len);
  268.   if(mc_simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
  269.     die("Error sending the log dump command");
  270.   
  271.   for(;;)
  272.   {
  273.     len = mc_net_safe_read(mysql);
  274.     if (len == packet_error)
  275.       die("Error reading packet from server: %s", mc_mysql_error(mysql));
  276.     if(len == 1 && net->read_pos[0] == 254)
  277.       break; // end of data
  278.     DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %dn",
  279. len, net->read_pos[5]));
  280.     Log_event * ev = Log_event::read_log_event(
  281.   (const char*) net->read_pos + 1 ,
  282.   len - 1);
  283.     if(ev)
  284.     {
  285.       ev->print(stdout, short_form);
  286.       if(ev->get_type_code() == LOAD_EVENT)
  287. dump_remote_file(net, ((Load_log_event*)ev)->fname);
  288.       delete ev;
  289.     }
  290.     else
  291.       die("Could not construct log event object");
  292.   }
  293. }
  294. static void dump_local_log_entries(const char* logname)
  295. {
  296.   File fd = -1;
  297.   IO_CACHE cache,*file= &cache;
  298.   ulonglong rec_count = 0;
  299.   if (logname && logname[0] != '-')
  300.   {
  301.     if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
  302.       exit(1);
  303.     if (init_io_cache(file, fd, 0, READ_CACHE, (my_off_t) position, 0,
  304.       MYF(MY_WME | MY_NABP)))
  305.       exit(1);
  306.   }
  307.   else
  308.   {
  309.     if (init_io_cache(file, fileno(stdout), 0, READ_CACHE, (my_off_t) 0,
  310.       0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
  311.       exit(1);
  312.     if (position)
  313.     {
  314.       /* skip 'position' characters from stdout */
  315.       byte buff[IO_SIZE];
  316.       my_off_t length,tmp;
  317.       for (length= (my_off_t) position ; length > 0 ; length-=tmp)
  318.       {
  319. tmp=min(length,sizeof(buff));
  320. if (my_b_read(file,buff, (uint) tmp))
  321.   exit(1);
  322.       }
  323.     }
  324.     file->pos_in_file=position;
  325.     file->seek_not_done=0;
  326.   }
  327.   if (!position)
  328.   {
  329.     char magic[4];
  330.     if (my_b_read(file, (byte*) magic, sizeof(magic)))
  331.       die("I/O error reading binlog magic number");
  332.     if(memcmp(magic, BINLOG_MAGIC, 4))
  333.       die("Bad magic number;  The file is probably not a MySQL binary log");
  334.   }
  335.  
  336.   for (;;)
  337.   {
  338.     char llbuff[21];
  339.     my_off_t old_off = my_b_tell(file);
  340.     Log_event* ev = Log_event::read_log_event(file, 0);
  341.     if (!ev)
  342.     {
  343.       if (file->error)
  344. die("
  345. Could not read entry at offset %s : Error in log format or read error",
  346.     llstr(old_off,llbuff));
  347.       // file->error == 0 means EOF, that's OK, we break in this case
  348.       break;
  349.     }
  350.     if (rec_count >= offset)
  351.     {
  352.       if (!short_form)
  353.         printf("# at %sn",llstr(old_off,llbuff));
  354.       ev->print(stdout, short_form);
  355.     }
  356.     rec_count++;
  357.     delete ev;
  358.   }
  359.   if(fd >= 0)
  360.    my_close(fd, MYF(MY_WME));
  361.   end_io_cache(file);
  362. }
  363. int main(int argc, char** argv)
  364. {
  365.   MY_INIT(argv[0]);
  366.   parse_args(&argc, (char***)&argv);
  367.   if(!argc && !table)
  368.   {
  369.     usage();
  370.     return -1;
  371.   }
  372.   if(use_remote)
  373.   {
  374. #ifndef __WIN__
  375.     init_thr_alarm(10); // need to do this manually 
  376. #endif
  377.     mysql = safe_connect();
  378.   }
  379.   if (table)
  380.   {
  381.     if(!use_remote)
  382.       die("You must specify connection parameter to get table dump");
  383.     char* db = (char*)table;
  384.     char* tbl = (char*) strchr(table, '.');
  385.     if(!tbl)
  386.       die("You must use database.table syntax to specify the table");
  387.     *tbl++ = 0;
  388.     dump_remote_table(&mysql->net, db, tbl);
  389.   }
  390.   else
  391.   {
  392.     while(--argc >= 0)
  393.     {
  394.       dump_log_entries(*(argv++));
  395.     }
  396.   }
  397.   if (use_remote)
  398.     mc_mysql_close(mysql);
  399.   return 0;
  400. }
  401. /*
  402.   We must include this here as it's compiled with different options for
  403.   the server
  404. */
  405. #include "log_event.cc"