home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / mysqlbinlog / mysqlbinlog.cpp < prev    next >
C/C++ Source or Header  |  2000-11-22  |  11KB  |  425 lines

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