mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	added error_code to query event, and checking to see if we get the expected error on the slave removed obsolete code from slave.cc
		
			
				
	
	
		
			384 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
 | 
						|
   
 | 
						|
   This program is free software; you can redistribute it and/or modify
 | 
						|
   it under the terms of the GNU General Public License as published by
 | 
						|
   the Free Software Foundation; either version 2 of the License, or
 | 
						|
   (at your option) any later version.
 | 
						|
   
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
   
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
						|
 | 
						|
 | 
						|
#define MYSQL_CLIENT
 | 
						|
#undef MYSQL_SERVER
 | 
						|
#include <global.h>
 | 
						|
#include <m_string.h>
 | 
						|
#include <my_sys.h>
 | 
						|
#include <getopt.h>
 | 
						|
#include <thr_alarm.h>
 | 
						|
#include "log_event.h"
 | 
						|
#define MYSQL_SERVER			// We want the C++ version of net
 | 
						|
#include <mysql.h>
 | 
						|
#include "mini_client.h"
 | 
						|
 | 
						|
#define CLIENT_CAPABILITIES	(CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
 | 
						|
 | 
						|
char server_version[50];
 | 
						|
uint32 server_id = 0;
 | 
						|
 | 
						|
// needed by net_serv.c
 | 
						|
ulong bytes_sent = 0L, bytes_received = 0L;
 | 
						|
ulong mysqld_net_retry_count = 10L;
 | 
						|
ulong net_read_timeout=  NET_READ_TIMEOUT;
 | 
						|
ulong net_write_timeout= NET_WRITE_TIMEOUT;
 | 
						|
uint test_flags = 0; 
 | 
						|
 | 
						|
#ifndef DBUG_OFF
 | 
						|
static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
 | 
						|
#endif
 | 
						|
 | 
						|
static struct option long_options[] =
 | 
						|
{
 | 
						|
  {"short-form", no_argument, 0, 's'},
 | 
						|
  {"table", required_argument, 0, 't'},
 | 
						|
  {"offset", required_argument,0, 'o'},
 | 
						|
  {"help", no_argument, 0, '?'},
 | 
						|
  {"host", required_argument,0, 'h'},
 | 
						|
  {"port", required_argument,0, 'P'},
 | 
						|
  {"user", required_argument,0, 'u'},
 | 
						|
  {"password", required_argument,0, 'p'},
 | 
						|
  {"position", required_argument,0, 'j'},
 | 
						|
#ifndef DBUG_OFF
 | 
						|
  {"debug", required_argument, 0, '#'}
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
void sql_print_error(const char *format,...);
 | 
						|
 | 
						|
static bool short_form = 0;
 | 
						|
static int offset = 0;
 | 
						|
static const char* host = "localhost";
 | 
						|
static int port = MYSQL_PORT;
 | 
						|
static const char* user = "test";
 | 
						|
static const char* pass = "";
 | 
						|
static long position = 0;
 | 
						|
static bool use_remote = 0;
 | 
						|
static short binlog_flags = 0; 
 | 
						|
static MYSQL* mysql = NULL;
 | 
						|
static const char* table = 0;
 | 
						|
 | 
						|
static void dump_local_log_entries(const char* logname);
 | 
						|
static void dump_remote_log_entries(const char* logname);
 | 
						|
static void dump_log_entries(const char* logname);
 | 
						|
static void dump_remote_file(NET* net, const char* fname);
 | 
						|
static void dump_remote_table(NET* net, const char* db, const char* table);
 | 
						|
static void die(const char* fmt, ...);
 | 
						|
static MYSQL* safe_connect();
 | 
						|
 | 
						|
 void sql_print_error(const char *format,...)
 | 
						|
 {
 | 
						|
  va_list args;
 | 
						|
  va_start(args, format);
 | 
						|
  fprintf(stderr, "ERROR: ");
 | 
						|
  vfprintf(stderr, format, args);
 | 
						|
  fprintf(stderr, "\n");
 | 
						|
  va_end(args);
 | 
						|
 }
 | 
						|
 | 
						|
static void die(const char* fmt, ...)
 | 
						|
{
 | 
						|
  va_list args;
 | 
						|
  va_start(args, fmt);
 | 
						|
  fprintf(stderr, "ERROR: ");
 | 
						|
  vfprintf(stderr, fmt, args);
 | 
						|
  fprintf(stderr, "\n");
 | 
						|
  va_end(args);
 | 
						|
  exit(1);
 | 
						|
}
 | 
						|
 | 
						|
static void usage()
 | 
						|
{
 | 
						|
  printf("Usage: %s [options] log-files\n",my_progname);
 | 
						|
  printf("Options:\n\
 | 
						|
-s,--short-form		just show the queries, no extra info\n\
 | 
						|
-o,--offset=N		skip the first N entries\n\
 | 
						|
-h,--host=server	get the binlog from server\n\
 | 
						|
-P,--port=port          use port to connect to the remove server\n\
 | 
						|
-u,--user=username      connect to the remove server as username\n\
 | 
						|
-p,--password=password  use this password to connect to remote server\n\
 | 
						|
-j,--position=N		start reading the binlog at postion N\n\
 | 
						|
-t,--table=name         get raw table dump using COM_TABLE_DUMB \n\
 | 
						|
-?,--help		this message\n");
 | 
						|
}
 | 
						|
 | 
						|
static void dump_remote_file(NET* net, const char* fname)
 | 
						|
{
 | 
						|
  char buf[FN_REFLEN+1];
 | 
						|
  uint len = (uint) strlen(fname);
 | 
						|
  buf[0] = 0;
 | 
						|
  memcpy(buf + 1, fname, len + 1);
 | 
						|
  if(my_net_write(net, buf, len +2) || net_flush(net))
 | 
						|
    die("Failed  requesting the remote dump of %s", fname);
 | 
						|
  for(;;)
 | 
						|
    {
 | 
						|
      uint packet_len = my_net_read(net);
 | 
						|
      if(packet_len == 0)
 | 
						|
	{
 | 
						|
	  if(my_net_write(net, "", 0) || net_flush(net))
 | 
						|
	    die("Failed sending the ack packet");
 | 
						|
 | 
						|
	  // we just need to send something, as the server will read but
 | 
						|
	  // not examine the packet - this is because mysql_load() sends an OK when it is done
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      else if(packet_len == packet_error)
 | 
						|
	die("Failed reading a packet during the dump of %s ", fname);
 | 
						|
 | 
						|
      if(!short_form)
 | 
						|
	(void)my_fwrite(stdout, (byte*) net->read_pos, packet_len, MYF(0));
 | 
						|
    }
 | 
						|
 | 
						|
  fflush(stdout);
 | 
						|
}
 | 
						|
 | 
						|
static int parse_args(int *argc, char*** argv)
 | 
						|
{
 | 
						|
  int c, opt_index = 0;
 | 
						|
 | 
						|
  while((c = getopt_long(*argc, *argv, "so:#:h:j:u:p:P:t:?", long_options,
 | 
						|
			 &opt_index)) != EOF)
 | 
						|
  {
 | 
						|
    switch(c)
 | 
						|
    {
 | 
						|
#ifndef DBUG_OFF
 | 
						|
    case '#':
 | 
						|
      DBUG_PUSH(optarg ? optarg : default_dbug_option);
 | 
						|
      break;
 | 
						|
#endif
 | 
						|
    case 's':
 | 
						|
      short_form = 1;
 | 
						|
      break;
 | 
						|
 | 
						|
    case 'o':
 | 
						|
      offset = atoi(optarg);
 | 
						|
      break;
 | 
						|
 | 
						|
    case 'j':
 | 
						|
      position = atoi(optarg);
 | 
						|
      break;
 | 
						|
 | 
						|
    case 'h':
 | 
						|
      use_remote = 1;
 | 
						|
      host = my_strdup(optarg, MYF(0));
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case 'P':
 | 
						|
      use_remote = 1;
 | 
						|
      port = atoi(optarg);
 | 
						|
      break;
 | 
						|
      
 | 
						|
    case 'p':
 | 
						|
      use_remote = 1;
 | 
						|
      pass = my_strdup(optarg, MYF(0));
 | 
						|
      break;
 | 
						|
 | 
						|
    case 'u':
 | 
						|
      use_remote = 1;
 | 
						|
      user = my_strdup(optarg, MYF(0));
 | 
						|
      break;
 | 
						|
 | 
						|
    case 't':
 | 
						|
      table = my_strdup(optarg, MYF(0));
 | 
						|
      break;
 | 
						|
 | 
						|
    case '?':
 | 
						|
    default:
 | 
						|
      usage();
 | 
						|
      exit(0);
 | 
						|
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  (*argc)-=optind;
 | 
						|
  (*argv)+=optind;
 | 
						|
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static MYSQL* safe_connect()
 | 
						|
{
 | 
						|
  MYSQL *local_mysql = mc_mysql_init(NULL);
 | 
						|
  if(!local_mysql)
 | 
						|
    die("Failed on mc_mysql_init");
 | 
						|
 | 
						|
  if(!mc_mysql_connect(local_mysql, host, user, pass, 0, port, 0, 0))
 | 
						|
    die("failed on connect: %s", mc_mysql_error(local_mysql));
 | 
						|
 | 
						|
  return local_mysql;
 | 
						|
}
 | 
						|
 | 
						|
static void dump_log_entries(const char* logname)
 | 
						|
{
 | 
						|
  if(use_remote)
 | 
						|
    dump_remote_log_entries(logname);
 | 
						|
  else
 | 
						|
    dump_local_log_entries(logname);  
 | 
						|
}
 | 
						|
 | 
						|
static void dump_remote_table(NET* net, const char* db, const char* table)
 | 
						|
{
 | 
						|
  char buf[1024];
 | 
						|
  char * p = buf;
 | 
						|
  uint table_len = (uint) strlen(table);
 | 
						|
  uint db_len = (uint) strlen(db);
 | 
						|
  if(table_len + db_len > sizeof(buf) - 2)
 | 
						|
    die("Buffer overrun");
 | 
						|
  
 | 
						|
  *p++ = db_len;
 | 
						|
  memcpy(p, db, db_len);
 | 
						|
  p += db_len;
 | 
						|
  *p++ = table_len;
 | 
						|
  memcpy(p, table, table_len);
 | 
						|
  
 | 
						|
  if(mc_simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
 | 
						|
    die("Error sending the table dump command");
 | 
						|
 | 
						|
  for(;;)
 | 
						|
    {
 | 
						|
      uint packet_len = my_net_read(net);
 | 
						|
      if(packet_len == 0) break; // end of file
 | 
						|
      if(packet_len == packet_error)
 | 
						|
	die("Error reading packet in table dump");
 | 
						|
      my_fwrite(stdout, (byte*)net->read_pos, packet_len, MYF(MY_WME));
 | 
						|
      fflush(stdout);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void dump_remote_log_entries(const char* logname)
 | 
						|
{
 | 
						|
  char buf[128];
 | 
						|
  uint len;
 | 
						|
  NET* net = &mysql->net;
 | 
						|
  int4store(buf, position);
 | 
						|
  int2store(buf + 4, binlog_flags);
 | 
						|
  len = (uint) strlen(logname);
 | 
						|
  int4store(buf + 6, 0);
 | 
						|
  memcpy(buf + 10, logname,len);
 | 
						|
  if(mc_simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
 | 
						|
    die("Error sending the log dump command");
 | 
						|
  
 | 
						|
  for(;;)
 | 
						|
  {
 | 
						|
    len = mc_net_safe_read(mysql);
 | 
						|
    if (len == packet_error)
 | 
						|
      die("Error reading packet from server: %s", mc_mysql_error(mysql));
 | 
						|
    if(len == 1 && net->read_pos[0] == 254)
 | 
						|
      break; // end of data
 | 
						|
    DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n",
 | 
						|
			len, net->read_pos[5]));
 | 
						|
    Log_event * ev = Log_event::read_log_event(
 | 
						|
					  (const char*) net->read_pos + 1 ,
 | 
						|
					  len);
 | 
						|
    if(ev)
 | 
						|
    {
 | 
						|
      ev->print(stdout, short_form);
 | 
						|
      if(ev->get_type_code() == LOAD_EVENT)
 | 
						|
	dump_remote_file(net, ((Load_log_event*)ev)->fname);
 | 
						|
      delete ev;
 | 
						|
    }
 | 
						|
    else
 | 
						|
      die("Could not construct log event object");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void dump_local_log_entries(const char* logname)
 | 
						|
{
 | 
						|
 FILE* file;
 | 
						|
 int rec_count = 0;
 | 
						|
 | 
						|
 if(logname && logname[0] != '-')
 | 
						|
   file = my_fopen(logname, O_RDONLY, MYF(MY_WME));
 | 
						|
 else
 | 
						|
   file = stdin;
 | 
						|
 | 
						|
 if(!file)
 | 
						|
   die("Could not open log file %s", logname);
 | 
						|
 | 
						|
 if(my_fseek(file, position, MY_SEEK_SET, MYF(MY_WME)))
 | 
						|
   die("failed on my_fseek()");
 | 
						|
 
 | 
						|
 while(1)
 | 
						|
   {
 | 
						|
     Log_event* ev = Log_event::read_log_event(file, 0);
 | 
						|
     if(!ev)
 | 
						|
       if(!feof(file))
 | 
						|
	die("Could not read entry at offset %ld : Error in log format or \
 | 
						|
read error",
 | 
						|
	   my_ftell(file, MYF(MY_WME)));
 | 
						|
       else
 | 
						|
	 break;
 | 
						|
 | 
						|
     if(rec_count >= offset)
 | 
						|
       ev->print(stdout, short_form);
 | 
						|
     rec_count++;
 | 
						|
     delete ev;
 | 
						|
   }
 | 
						|
 | 
						|
 my_fclose(file, MYF(MY_WME));
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char** argv)
 | 
						|
{
 | 
						|
  MY_INIT(argv[0]);
 | 
						|
  parse_args(&argc, (char***)&argv);
 | 
						|
 | 
						|
  if(!argc && !table)
 | 
						|
    {
 | 
						|
      usage();
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  if(use_remote)
 | 
						|
    {
 | 
						|
      init_thr_alarm(10); // need to do this manually 
 | 
						|
      mysql = safe_connect();
 | 
						|
    }
 | 
						|
 | 
						|
  if(table)
 | 
						|
    {
 | 
						|
      if(!use_remote)
 | 
						|
	die("You must specify connection parameter to get table dump");
 | 
						|
      char* db = (char*)table;
 | 
						|
      char* tbl = (char*) strchr(table, '.');
 | 
						|
      if(!tbl)
 | 
						|
	die("You must use database.table syntax to specify the table");
 | 
						|
      *tbl++ = 0;
 | 
						|
      dump_remote_table(&mysql->net, db, tbl);
 | 
						|
    }
 | 
						|
  else
 | 
						|
   while(--argc >= 0)
 | 
						|
    {
 | 
						|
      dump_log_entries(*(argv++));
 | 
						|
    }
 | 
						|
 | 
						|
  if(use_remote)
 | 
						|
    mc_mysql_close(mysql);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  We must include this here as it's compiled with different options for
 | 
						|
  the server
 | 
						|
*/
 | 
						|
 | 
						|
#include "log_event.cc"
 |