2002-09-14 18:26:40 +02:00
/* Copyright (C) 2001 MySQL AB
2001-12-06 13:10:51 +01:00
2000-07-31 21:29:14 +02:00
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 .
2001-12-06 13:10:51 +01:00
2000-07-31 21:29:14 +02:00
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 .
2001-12-06 13:10:51 +01:00
2000-07-31 21:29:14 +02:00
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
2001-09-12 22:53:31 +02:00
# include "client_priv.h"
2001-08-30 20:16:39 +02:00
# include <time.h>
2003-07-04 22:06:17 +02:00
# include <assert.h>
2001-01-21 15:30:16 +01:00
# include "log_event.h"
2003-07-04 22:06:17 +02:00
# include "include/my_sys.h"
2000-07-31 21:29:14 +02:00
2002-06-11 10:20:31 +02:00
# define BIN_LOG_HEADER_SIZE 4
2002-09-11 05:40:08 +02:00
# define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
2002-06-11 10:20:31 +02:00
2001-11-11 06:24:12 +01:00
2000-07-31 21:29:14 +02:00
# define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
2001-01-21 15:30:16 +01:00
char server_version [ SERVER_VERSION_LENGTH ] ;
2003-03-05 14:34:58 +01:00
ulong server_id = 0 ;
2000-07-31 21:29:14 +02:00
// needed by net_serv.c
ulong bytes_sent = 0L , bytes_received = 0L ;
ulong mysqld_net_retry_count = 10L ;
uint test_flags = 0 ;
2001-09-12 22:53:31 +02:00
static FILE * result_file ;
2000-07-31 21:29:14 +02:00
# ifndef DBUG_OFF
static const char * default_dbug_option = " d:t:o,/tmp/mysqlbinlog.trace " ;
# endif
2002-09-14 18:26:40 +02:00
void sql_print_error ( const char * format , . . . ) ;
2000-07-31 21:29:14 +02:00
2002-05-16 22:35:09 +02:00
static bool one_database = 0 ;
2003-04-23 15:00:07 +02:00
static bool force_opt = 0 ;
2002-05-16 22:35:09 +02:00
static const char * database ;
2000-07-31 21:29:14 +02:00
static bool short_form = 0 ;
2001-01-03 15:54:46 +01:00
static ulonglong offset = 0 ;
2000-07-31 21:29:14 +02:00
static const char * host = " localhost " ;
static int port = MYSQL_PORT ;
2003-07-04 22:06:17 +02:00
static const char * sock = MYSQL_UNIX_ADDR ;
2000-07-31 21:29:14 +02:00
static const char * user = " test " ;
static const char * pass = " " ;
2001-01-03 15:54:46 +01:00
static ulonglong position = 0 ;
2000-07-31 21:29:14 +02:00
static bool use_remote = 0 ;
static short binlog_flags = 0 ;
static MYSQL * mysql = NULL ;
2003-07-04 22:06:17 +02:00
static const char * dirname_for_local_load = 0 ;
2000-07-31 21:29:14 +02:00
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 die ( const char * fmt , . . . ) ;
static MYSQL * safe_connect ( ) ;
2003-07-04 22:06:17 +02:00
class Load_log_processor
{
char target_dir_name [ MY_NFILE ] ;
int target_dir_name_len ;
DYNAMIC_ARRAY file_names ;
const char * create_file ( Create_file_log_event * ce )
{
const char * bname = ce - > fname + ce - > fname_len - 1 ;
while ( bname > ce - > fname & & bname [ - 1 ] ! = FN_LIBCHAR )
bname - - ;
uint blen = ce - > fname_len - ( bname - ce - > fname ) ;
uint full_len = target_dir_name_len + blen ;
char * tmp ;
if ( ! ( tmp = my_malloc ( full_len + 9 + 1 , MYF ( MY_WME ) ) ) | |
set_dynamic ( & file_names , ( gptr ) & ce , ce - > file_id ) )
{
die ( " Could not construct local filename %s%s " , target_dir_name , bname ) ;
return 0 ;
}
char * ptr = tmp ;
memcpy ( ptr , target_dir_name , target_dir_name_len ) ;
ptr + = target_dir_name_len ;
memcpy ( ptr , bname , blen ) ;
ptr + = blen ;
sprintf ( ptr , " -%08x " , ce - > file_id ) ;
ce - > set_fname_outside_temp_buf ( tmp , full_len ) ;
return tmp ;
}
void append_to_file ( const char * fname , int flags ,
gptr data , uint size )
{
File file ;
if ( ( ( file = my_open ( fname , flags , MYF ( MY_WME ) ) ) < 0 ) | |
my_write ( file , ( byte * ) data , size , MYF ( MY_WME | MY_NABP ) ) | |
my_close ( file , MYF ( MY_WME ) ) )
exit ( 1 ) ;
}
public :
Load_log_processor ( )
{
init_dynamic_array ( & file_names , sizeof ( Create_file_log_event * ) ,
100 , 100 CALLER_INFO ) ;
}
~ Load_log_processor ( )
{
destroy ( ) ;
delete_dynamic ( & file_names ) ;
}
void init_by_dir_name ( const char * atarget_dir_name )
{
char * end = strmov ( target_dir_name , atarget_dir_name ) ;
if ( end [ - 1 ] ! = FN_LIBCHAR )
* end + + = FN_LIBCHAR ;
target_dir_name_len = end - target_dir_name ;
}
void init_by_file_name ( const char * file_name )
{
int len = strlen ( file_name ) ;
const char * end = file_name + len - 1 ;
while ( end > file_name & & * end ! = FN_LIBCHAR )
end - - ;
if ( * end ! = FN_LIBCHAR )
target_dir_name_len = 0 ;
else
{
target_dir_name_len = end - file_name + 1 ;
memmove ( target_dir_name , file_name , target_dir_name_len ) ;
}
}
void init_by_cur_dir ( )
{
if ( my_getwd ( target_dir_name , sizeof ( target_dir_name ) , MYF ( MY_WME ) ) )
exit ( 1 ) ;
target_dir_name_len = strlen ( target_dir_name ) ;
}
void destroy ( )
{
Create_file_log_event * * ptr = ( Create_file_log_event * * ) file_names . buffer ;
Create_file_log_event * * end = ptr + file_names . elements ;
for ( ; ptr < end ; ptr + + )
{
if ( * ptr )
{
my_free ( ( char * ) ( * ptr ) - > fname , MYF ( MY_WME ) ) ;
delete * ptr ;
* ptr = 0 ;
}
}
}
Create_file_log_event * grab_event ( uint file_id )
{
Create_file_log_event * * ptr =
( Create_file_log_event * * ) file_names . buffer + file_id ;
Create_file_log_event * res = * ptr ;
* ptr = 0 ;
return res ;
}
void process ( Create_file_log_event * ce )
{
const char * fname = create_file ( ce ) ;
append_to_file ( fname , O_CREAT | O_EXCL | O_BINARY | O_WRONLY , ce - > block , ce - > block_len ) ;
}
void process ( Append_block_log_event * ae )
{
if ( ae - > file_id > = file_names . elements )
die ( " Skiped CreateFile event for file_id: %u " , ae - > file_id ) ;
Create_file_log_event * ce =
* ( ( Create_file_log_event * * ) file_names . buffer + ae - > file_id ) ;
append_to_file ( ce - > fname , O_APPEND | O_BINARY | O_WRONLY , ae - > block , ae - > block_len ) ;
}
} ;
Load_log_processor load_processor ;
2002-05-21 23:05:05 +02:00
static struct my_option my_long_options [ ] =
{
# ifndef DBUG_OFF
{ " debug " , ' # ' , " Output debug log. " , ( gptr * ) & default_dbug_option ,
( gptr * ) & default_dbug_option , 0 , GET_STR , OPT_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
# endif
2003-07-04 22:06:17 +02:00
{ " database " , ' d ' , " List entries for just this database (local log only). " ,
2002-05-21 23:05:05 +02:00
( gptr * ) & database , ( gptr * ) & database , 0 , GET_STR_ALLOC , REQUIRED_ARG ,
0 , 0 , 0 , 0 , 0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " force-read " , ' f ' , " Force reading unknown binlog events. " ,
2003-04-23 15:00:07 +02:00
( gptr * ) & force_opt , ( gptr * ) & force_opt , 0 , GET_BOOL , NO_ARG , 0 , 0 , 0 , 0 ,
0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " help " , ' ? ' , " Display this help and exit. " ,
2002-05-21 23:05:05 +02:00
0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " host " , ' h ' , " Get the binlog from server. " , ( gptr * ) & host , ( gptr * ) & host ,
2002-05-21 23:05:05 +02:00
0 , GET_STR_ALLOC , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " offset " , ' o ' , " Skip the first N entries. " , ( gptr * ) & offset , ( gptr * ) & offset ,
2002-05-21 23:05:05 +02:00
0 , GET_ULL , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " password " , ' p ' , " Password to connect to remote server. " ,
2002-05-21 23:05:05 +02:00
0 , 0 , 0 , GET_STR , REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " port " , ' P ' , " Use port to connect to the remote server. " ,
2002-05-21 23:05:05 +02:00
( gptr * ) & port , ( gptr * ) & port , 0 , GET_INT , REQUIRED_ARG , MYSQL_PORT , 0 , 0 ,
0 , 0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " position " , ' j ' , " Start reading the binlog at position N. " ,
2002-05-21 23:05:05 +02:00
( gptr * ) & position , ( gptr * ) & position , 0 , GET_ULL , REQUIRED_ARG , 0 , 0 , 0 , 0 ,
0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " result-file " , ' r ' , " Direct output to a given file. " , 0 , 0 , 0 , GET_STR ,
2002-05-21 23:05:05 +02:00
REQUIRED_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " short-form " , ' s ' , " Just show the queries, no extra info. " ,
2002-05-21 23:05:05 +02:00
( gptr * ) & short_form , ( gptr * ) & short_form , 0 , GET_BOOL , NO_ARG , 0 , 0 , 0 , 0 ,
0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " socket " , ' S ' , " Socket file to use for connection. " ,
( gptr * ) & sock , ( gptr * ) & sock , 0 , GET_STR_ALLOC , REQUIRED_ARG , 0 , 0 , 0 , 0 ,
0 , 0 } ,
{ " user " , ' u ' , " Connect to the remote server as username. " ,
2002-05-21 23:05:05 +02:00
( gptr * ) & user , ( gptr * ) & user , 0 , GET_STR_ALLOC , REQUIRED_ARG , 0 , 0 , 0 , 0 ,
0 , 0 } ,
2003-07-04 22:06:17 +02:00
{ " local-load " , ' l ' , " Prepare files for local load in directory. " ,
( gptr * ) & dirname_for_local_load , ( gptr * ) & dirname_for_local_load , 0 ,
GET_STR_ALLOC , OPT_ARG , 0 , 0 , 0 , 0 , 0 , 0 } ,
2002-05-21 23:05:05 +02:00
{ " version " , ' V ' , " Print version and exit. " , 0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 ,
0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , GET_NO_ARG , NO_ARG , 0 , 0 , 0 , 0 , 0 , 0 }
} ;
2001-02-06 21:32:19 +01:00
void sql_print_error ( const char * format , . . . )
{
2000-07-31 21:29:14 +02:00
va_list args ;
va_start ( args , format ) ;
fprintf ( stderr , " ERROR: " ) ;
vfprintf ( stderr , format , args ) ;
fprintf ( stderr , " \n " ) ;
va_end ( args ) ;
2001-02-06 21:32:19 +01:00
}
2000-07-31 21:29:14 +02:00
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 ) ;
}
2001-02-06 21:32:19 +01:00
static void print_version ( )
{
2002-05-29 14:07:30 +02:00
printf ( " %s Ver 2.3 for %s at %s \n " , my_progname , SYSTEM_TYPE , MACHINE_TYPE ) ;
2001-02-06 21:32:19 +01:00
}
2000-07-31 21:29:14 +02:00
static void usage ( )
{
2001-02-06 21:32:19 +01:00
print_version ( ) ;
2002-04-23 17:17:00 +02:00
puts ( " By Monty and Sasha, for your professional use \n \
This software comes with NO WARRANTY : This is free software , \ n \
and you are welcome to modify and redistribute it under the GPL license \ n " );
2001-02-06 21:32:19 +01:00
printf ( " \
2002-09-14 18:12:02 +02:00
Dumps a MySQL binary log in a format usable for viewing or for piping to \ n \
2001-02-06 21:32:19 +01:00
the mysql command line client \ n \ n " );
2002-05-21 23:05:05 +02:00
printf ( " Usage: %s [options] log-files \n " , my_progname ) ;
my_print_help ( my_long_options ) ;
my_print_variables ( my_long_options ) ;
2000-07-31 21:29:14 +02:00
}
static void dump_remote_file ( NET * net , const char * fname )
{
char buf [ FN_REFLEN + 1 ] ;
2000-08-21 23:18:32 +02:00
uint len = ( uint ) strlen ( fname ) ;
2000-07-31 21:29:14 +02:00
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 )
2001-04-26 00:12:51 +02:00
( void ) my_fwrite ( result_file , ( byte * ) net - > read_pos , packet_len , MYF ( 0 ) ) ;
2000-07-31 21:29:14 +02:00
}
2001-04-26 00:12:51 +02:00
fflush ( result_file ) ;
2000-07-31 21:29:14 +02:00
}
2002-11-07 11:49:02 +01:00
extern " C " my_bool
2002-05-21 23:05:05 +02:00
get_one_option ( int optid , const struct my_option * opt __attribute__ ( ( unused ) ) ,
char * argument )
{
2003-07-04 22:06:17 +02:00
switch ( optid ) {
2000-07-31 21:29:14 +02:00
# ifndef DBUG_OFF
2002-05-21 23:05:05 +02:00
case ' # ' :
DBUG_PUSH ( argument ? argument : default_dbug_option ) ;
break ;
2000-07-31 21:29:14 +02:00
# endif
2002-05-21 23:05:05 +02:00
case ' d ' :
one_database = 1 ;
break ;
case ' h ' :
use_remote = 1 ;
break ;
case ' P ' :
use_remote = 1 ;
break ;
case ' p ' :
use_remote = 1 ;
pass = my_strdup ( argument , MYF ( 0 ) ) ;
break ;
case ' r ' :
if ( ! ( result_file = my_fopen ( argument , O_WRONLY | O_BINARY , MYF ( MY_WME ) ) ) )
exit ( 1 ) ;
break ;
case ' u ' :
use_remote = 1 ;
break ;
case ' V ' :
print_version ( ) ;
exit ( 0 ) ;
case ' ? ' :
usage ( ) ;
exit ( 0 ) ;
2000-07-31 21:29:14 +02:00
}
2002-05-21 23:05:05 +02:00
return 0 ;
}
2000-07-31 21:29:14 +02:00
2002-05-21 23:05:05 +02:00
static int parse_args ( int * argc , char * * * argv )
{
int ho_error ;
2000-07-31 21:29:14 +02:00
2002-05-21 23:05:05 +02:00
result_file = stdout ;
if ( ( ho_error = handle_options ( argc , argv , my_long_options , get_one_option ) ) )
2002-05-29 14:07:30 +02:00
exit ( ho_error ) ;
2000-07-31 21:29:14 +02:00
return 0 ;
}
static MYSQL * safe_connect ( )
{
2001-08-10 02:16:43 +02:00
MYSQL * local_mysql = mysql_init ( NULL ) ;
2000-07-31 21:29:14 +02:00
if ( ! local_mysql )
2001-08-10 02:16:43 +02:00
die ( " Failed on mysql_init " ) ;
2000-07-31 21:29:14 +02:00
2003-07-04 22:06:17 +02:00
if ( ! mysql_real_connect ( local_mysql , host , user , pass , 0 , port , sock , 0 ) )
2001-08-10 02:16:43 +02:00
die ( " failed on connect: %s " , mysql_error ( local_mysql ) ) ;
2000-07-31 21:29:14 +02:00
return local_mysql ;
}
static void dump_log_entries ( const char * logname )
{
2002-06-11 10:20:31 +02:00
if ( use_remote )
2000-07-31 21:29:14 +02:00
dump_remote_log_entries ( logname ) ;
else
dump_local_log_entries ( logname ) ;
}
2001-11-11 06:24:12 +01:00
static int check_master_version ( MYSQL * mysql )
{
MYSQL_RES * res = 0 ;
MYSQL_ROW row ;
const char * version ;
int old_format = 0 ;
2001-12-06 13:10:51 +01:00
2002-06-11 10:20:31 +02:00
if ( mysql_query ( mysql , " SELECT VERSION() " ) | |
! ( res = mysql_store_result ( mysql ) ) )
2001-11-11 06:24:12 +01:00
{
mysql_close ( mysql ) ;
die ( " Error checking master version: %s " ,
mysql_error ( mysql ) ) ;
}
if ( ! ( row = mysql_fetch_row ( res ) ) )
{
mysql_free_result ( res ) ;
mysql_close ( mysql ) ;
die ( " Master returned no rows for SELECT VERSION() " ) ;
return 1 ;
}
if ( ! ( version = row [ 0 ] ) )
{
mysql_free_result ( res ) ;
mysql_close ( mysql ) ;
die ( " Master reported NULL for the version " ) ;
}
2001-12-06 13:10:51 +01:00
2002-06-11 10:20:31 +02:00
switch ( * version ) {
2001-11-11 06:24:12 +01:00
case ' 3 ' :
old_format = 1 ;
break ;
case ' 4 ' :
2002-06-11 10:20:31 +02:00
case ' 5 ' :
2001-11-11 06:24:12 +01:00
old_format = 0 ;
break ;
default :
sql_print_error ( " Master reported unrecognized MySQL version '%s' " ,
version ) ;
mysql_free_result ( res ) ;
mysql_close ( mysql ) ;
return 1 ;
}
mysql_free_result ( res ) ;
return old_format ;
}
2000-07-31 21:29:14 +02:00
2002-06-11 10:20:31 +02:00
2000-07-31 21:29:14 +02:00
static void dump_remote_log_entries ( const char * logname )
{
char buf [ 128 ] ;
2001-04-25 01:39:26 +02:00
char last_db [ FN_REFLEN + 1 ] = " " ;
2000-07-31 21:29:14 +02:00
uint len ;
NET * net = & mysql - > net ;
2001-11-11 06:24:12 +01:00
int old_format ;
old_format = check_master_version ( mysql ) ;
2001-12-06 13:10:51 +01:00
2002-06-11 10:20:31 +02:00
if ( ! position )
position = BIN_LOG_HEADER_SIZE ; // protect the innocent from spam
if ( position < BIN_LOG_HEADER_SIZE )
2001-05-29 12:46:17 +02:00
{
2002-06-11 10:20:31 +02:00
position = BIN_LOG_HEADER_SIZE ;
2001-05-29 12:46:17 +02:00
// warn the guity
2002-06-11 10:20:31 +02:00
sql_print_error ( " Warning: The position in the binary log can't be less than %d. \n Starting from position %d \n " , BIN_LOG_HEADER_SIZE , BIN_LOG_HEADER_SIZE ) ;
2001-05-29 12:46:17 +02:00
}
2000-07-31 21:29:14 +02:00
int4store ( buf , position ) ;
2002-06-11 10:20:31 +02:00
int2store ( buf + BIN_LOG_HEADER_SIZE , binlog_flags ) ;
2000-08-21 23:18:32 +02:00
len = ( uint ) strlen ( logname ) ;
2000-09-30 01:20:26 +02:00
int4store ( buf + 6 , 0 ) ;
memcpy ( buf + 10 , logname , len ) ;
2001-11-11 06:24:12 +01:00
if ( simple_command ( mysql , COM_BINLOG_DUMP , buf , len + 10 , 1 ) )
2000-07-31 21:29:14 +02:00
die ( " Error sending the log dump command " ) ;
2001-12-06 13:10:51 +01:00
2002-06-11 10:20:31 +02:00
for ( ; ; )
2000-07-31 21:29:14 +02:00
{
2001-09-21 02:38:35 +02:00
const char * error ;
2001-08-10 02:16:43 +02:00
len = net_safe_read ( mysql ) ;
2000-07-31 21:29:14 +02:00
if ( len = = packet_error )
2001-08-10 02:16:43 +02:00
die ( " Error reading packet from server: %s " , mysql_error ( mysql ) ) ;
2003-07-02 22:56:27 +02:00
if ( len < 8 & & net - > read_pos [ 0 ] = = 254 )
2000-07-31 21:29:14 +02:00
break ; // end of data
DBUG_PRINT ( " info " , ( " len= %u, net->read_pos[5] = %d \n " ,
len , net - > read_pos [ 5 ] ) ) ;
2002-06-11 10:20:31 +02:00
Log_event * ev = Log_event : : read_log_event ( ( const char * ) net - > read_pos + 1 ,
len - 1 , & error , old_format ) ;
2001-09-21 02:38:35 +02:00
if ( ev )
2000-07-31 21:29:14 +02:00
{
2001-04-26 00:12:51 +02:00
ev - > print ( result_file , short_form , last_db ) ;
2002-06-11 10:20:31 +02:00
if ( ev - > get_type_code ( ) = = LOAD_EVENT )
2000-07-31 21:29:14 +02:00
dump_remote_file ( net , ( ( Load_log_event * ) ev ) - > fname ) ;
delete ev ;
}
else
die ( " Could not construct log event object " ) ;
}
}
2002-06-11 10:20:31 +02:00
2003-07-04 22:06:17 +02:00
static int check_header ( IO_CACHE * file )
2001-11-11 06:24:12 +01:00
{
2002-09-11 05:40:08 +02:00
byte header [ BIN_LOG_HEADER_SIZE ] ;
2001-12-09 23:08:24 +01:00
byte buf [ PROBE_HEADER_LEN ] ;
2002-06-11 10:20:31 +02:00
int old_format = 0 ;
2001-12-06 13:10:51 +01:00
2001-11-11 06:24:12 +01:00
my_off_t pos = my_b_tell ( file ) ;
my_b_seek ( file , ( my_off_t ) 0 ) ;
2002-09-11 05:40:08 +02:00
if ( my_b_read ( file , header , sizeof ( header ) ) )
die ( " Failed reading header; Probably an empty file " ) ;
if ( memcmp ( header , BINLOG_MAGIC , sizeof ( header ) ) )
2003-07-04 22:06:17 +02:00
die ( " File is not a binary log file " ) ;
2002-09-11 05:40:08 +02:00
if ( ! my_b_read ( file , buf , sizeof ( buf ) ) )
2001-11-11 06:24:12 +01:00
{
2002-09-11 05:40:08 +02:00
if ( buf [ 4 ] = = START_EVENT )
{
uint event_len ;
2003-06-20 15:48:52 +02:00
event_len = uint4korr ( buf + EVENT_LEN_OFFSET ) ;
old_format = ( event_len < ( LOG_EVENT_HEADER_LEN + START_HEADER_LEN ) ) ;
2002-09-11 05:40:08 +02:00
}
2001-11-11 06:24:12 +01:00
}
my_b_seek ( file , pos ) ;
return old_format ;
}
2002-09-11 05:40:08 +02:00
2000-07-31 21:29:14 +02:00
static void dump_local_log_entries ( const char * logname )
{
2000-11-17 01:48:13 +01:00
File fd = - 1 ;
2000-11-15 22:00:06 +01:00
IO_CACHE cache , * file = & cache ;
2001-01-03 15:54:46 +01:00
ulonglong rec_count = 0 ;
2002-09-19 16:49:41 +02:00
char last_db [ FN_REFLEN + 1 ] ;
byte tmp_buff [ BIN_LOG_HEADER_SIZE ] ;
2001-11-11 06:24:12 +01:00
bool old_format = 0 ;
2000-11-15 22:00:06 +01:00
2002-09-11 05:40:08 +02:00
last_db [ 0 ] = 0 ;
2000-11-15 22:00:06 +01:00
if ( logname & & logname [ 0 ] ! = ' - ' )
{
if ( ( fd = my_open ( logname , O_RDONLY | O_BINARY , MYF ( MY_WME ) ) ) < 0 )
exit ( 1 ) ;
if ( init_io_cache ( file , fd , 0 , READ_CACHE , ( my_off_t ) position , 0 ,
MYF ( MY_WME | MY_NABP ) ) )
exit ( 1 ) ;
2003-07-04 22:06:17 +02:00
old_format = check_header ( file ) ;
2000-11-15 22:00:06 +01:00
}
else
{
2001-04-26 00:12:51 +02:00
if ( init_io_cache ( file , fileno ( result_file ) , 0 , READ_CACHE , ( my_off_t ) 0 ,
2000-11-15 22:00:06 +01:00
0 , MYF ( MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE ) ) )
exit ( 1 ) ;
2003-07-04 22:06:17 +02:00
old_format = check_header ( file ) ;
2000-11-15 22:00:06 +01:00
if ( position )
{
/* skip 'position' characters from stdout */
2000-11-18 01:15:06 +01:00
byte buff [ IO_SIZE ] ;
2000-11-15 22:00:06 +01:00
my_off_t length , tmp ;
2001-01-03 15:54:46 +01:00
for ( length = ( my_off_t ) position ; length > 0 ; length - = tmp )
2000-11-15 22:00:06 +01:00
{
tmp = min ( length , sizeof ( buff ) ) ;
2002-06-11 10:20:31 +02:00
if ( my_b_read ( file , buff , ( uint ) tmp ) )
2000-11-15 22:00:06 +01:00
exit ( 1 ) ;
}
}
file - > pos_in_file = position ;
file - > seek_not_done = 0 ;
}
if ( ! position )
2002-09-11 05:40:08 +02:00
my_b_read ( file , tmp_buff , BIN_LOG_HEADER_SIZE ) ; // Skip header
2001-02-15 02:43:14 +01:00
for ( ; ; )
2000-11-15 22:00:06 +01:00
{
2001-01-03 15:54:46 +01:00
char llbuff [ 21 ] ;
2001-02-06 21:32:19 +01:00
my_off_t old_off = my_b_tell ( file ) ;
2001-11-11 06:24:12 +01:00
Log_event * ev = Log_event : : read_log_event ( file , old_format ) ;
2000-11-15 22:00:06 +01:00
if ( ! ev )
{
if ( file - > error )
2001-01-03 15:54:46 +01:00
die ( " \
Could not read entry at offset % s : Error in log format or read error " ,
2001-02-06 21:32:19 +01:00
llstr ( old_off , llbuff ) ) ;
2000-11-26 07:29:01 +01:00
// file->error == 0 means EOF, that's OK, we break in this case
2000-11-15 22:00:06 +01:00
break ;
}
if ( rec_count > = offset )
2001-02-06 21:32:19 +01:00
{
2002-05-16 22:35:09 +02:00
// see if we should skip this event (only care about queries for now)
if ( one_database )
{
if ( ev - > get_type_code ( ) = = QUERY_EVENT )
{
//const char * log_dbname = ev->get_db();
const char * log_dbname = ( ( Query_log_event * ) ev ) - > db ;
//printf("entry: %llu, database: %s\n", rec_count, log_dbname);
if ( ( log_dbname ! = NULL ) & & ( strcmp ( log_dbname , database ) ) )
{
//printf("skipping, %s is not %s\n", log_dbname, database);
rec_count + + ;
delete ev ;
continue ; // next
}
# ifndef DBUG_OFF
else
{
printf ( " no skip \n " ) ;
}
# endif
}
# ifndef DBUG_OFF
else
{
const char * query_type = ev - > get_type_str ( ) ;
printf ( " not query -- %s \n " , query_type ) ;
}
# endif
}
2001-02-06 21:32:19 +01:00
if ( ! short_form )
2001-04-26 00:12:51 +02:00
fprintf ( result_file , " # at %s \n " , llstr ( old_off , llbuff ) ) ;
2003-07-04 22:06:17 +02:00
switch ( ev - > get_type_code ( ) ) {
case CREATE_FILE_EVENT :
{
Create_file_log_event * ce = ( Create_file_log_event * ) ev ;
ce - > print ( result_file , short_form , last_db , true ) ;
load_processor . process ( ce ) ;
ev = 0 ;
break ;
}
case APPEND_BLOCK_EVENT :
ev - > print ( result_file , short_form , last_db ) ;
load_processor . process ( ( Append_block_log_event * ) ev ) ;
break ;
case EXEC_LOAD_EVENT :
{
ev - > print ( result_file , short_form , last_db ) ;
Execute_load_log_event * exv = ( Execute_load_log_event * ) ev ;
Create_file_log_event * ce = load_processor . grab_event ( exv - > file_id ) ;
ce - > print ( result_file , short_form , last_db , true ) ;
my_free ( ( char * ) ce - > fname , MYF ( MY_WME ) ) ;
delete ce ;
break ;
}
default :
ev - > print ( result_file , short_form , last_db ) ;
}
2001-02-06 21:32:19 +01:00
}
2000-11-15 22:00:06 +01:00
rec_count + + ;
2003-07-04 22:06:17 +02:00
if ( ev )
delete ev ;
2000-11-15 22:00:06 +01:00
}
2002-06-11 10:20:31 +02:00
if ( fd > = 0 )
2000-11-17 01:48:13 +01:00
my_close ( fd , MYF ( MY_WME ) ) ;
2000-11-15 22:00:06 +01:00
end_io_cache ( file ) ;
2000-07-31 21:29:14 +02:00
}
2003-07-04 22:06:17 +02:00
# if MYSQL_VERSION_ID < 40101
typedef struct st_my_tmpdir
{
char * * list ;
uint cur , max ;
} MY_TMPDIR ;
# if defined( __WIN__) || defined(OS2)
# define DELIM ';'
# else
# define DELIM ':'
# endif
my_bool init_tmpdir ( MY_TMPDIR * tmpdir , const char * pathlist )
{
char * end , * copy ;
char buff [ FN_REFLEN ] ;
DYNAMIC_ARRAY t_arr ;
if ( my_init_dynamic_array ( & t_arr , sizeof ( char * ) , 1 , 5 ) )
return TRUE ;
if ( ! pathlist | | ! pathlist [ 0 ] )
{
/* Get default temporary directory */
pathlist = getenv ( " TMPDIR " ) ; /* Use this if possible */
# if defined( __WIN__) || defined(OS2)
if ( ! pathlist )
pathlist = getenv ( " TEMP " ) ;
if ( ! pathlist )
pathlist = getenv ( " TMP " ) ;
# endif
if ( ! pathlist | | ! pathlist [ 0 ] )
pathlist = ( char * ) P_tmpdir ;
}
do
{
end = strcend ( pathlist , DELIM ) ;
convert_dirname ( buff , pathlist , end ) ;
if ( ! ( copy = my_strdup ( buff , MYF ( MY_WME ) ) ) )
return TRUE ;
if ( insert_dynamic ( & t_arr , ( gptr ) & copy ) )
return TRUE ;
pathlist = end + 1 ;
}
while ( * end ) ;
freeze_size ( & t_arr ) ;
tmpdir - > list = ( char * * ) t_arr . buffer ;
tmpdir - > max = t_arr . elements - 1 ;
tmpdir - > cur = 0 ;
return FALSE ;
}
char * my_tmpdir ( MY_TMPDIR * tmpdir )
{
char * dir ;
dir = tmpdir - > list [ tmpdir - > cur ] ;
tmpdir - > cur = ( tmpdir - > cur = = tmpdir - > max ) ? 0 : tmpdir - > cur + 1 ;
return dir ;
}
void free_tmpdir ( MY_TMPDIR * tmpdir )
{
uint i ;
for ( i = 0 ; i < = tmpdir - > max ; i + + )
my_free ( tmpdir - > list [ i ] , MYF ( 0 ) ) ;
my_free ( ( gptr ) tmpdir - > list , MYF ( 0 ) ) ;
}
# endif
2000-11-15 22:00:06 +01:00
2000-07-31 21:29:14 +02:00
int main ( int argc , char * * argv )
{
MY_INIT ( argv [ 0 ] ) ;
parse_args ( & argc , ( char * * * ) & argv ) ;
2003-07-01 19:17:03 +02:00
if ( ! argc )
2000-11-15 22:00:06 +01:00
{
usage ( ) ;
return - 1 ;
}
2000-07-31 21:29:14 +02:00
2002-06-11 10:20:31 +02:00
if ( use_remote )
2000-11-15 22:00:06 +01:00
mysql = safe_connect ( ) ;
2000-07-31 21:29:14 +02:00
2003-07-04 22:06:17 +02:00
MY_TMPDIR tmpdir ;
tmpdir . list = 0 ;
if ( ! dirname_for_local_load )
{
if ( init_tmpdir ( & tmpdir , 0 ) )
exit ( 1 ) ;
dirname_for_local_load = my_tmpdir ( & tmpdir ) ;
}
if ( dirname_for_local_load )
load_processor . init_by_dir_name ( dirname_for_local_load ) ;
else
load_processor . init_by_cur_dir ( ) ;
2003-07-01 19:17:03 +02:00
while ( - - argc > = 0 )
dump_log_entries ( * ( argv + + ) ) ;
2003-07-04 22:06:17 +02:00
if ( tmpdir . list )
free_tmpdir ( & tmpdir ) ;
2001-04-26 00:12:51 +02:00
if ( result_file ! = stdout )
my_fclose ( result_file , MYF ( 0 ) ) ;
2000-11-15 22:00:06 +01:00
if ( use_remote )
2001-08-10 02:16:43 +02:00
mysql_close ( mysql ) ;
2000-07-31 21:29:14 +02:00
return 0 ;
}
/*
We must include this here as it ' s compiled with different options for
the server
*/
2001-08-11 13:10:27 +02:00
# ifdef __WIN__
# include "log_event.cpp"
# else
2000-07-31 21:29:14 +02:00
# include "log_event.cc"
2001-08-11 13:10:27 +02:00
# endif
2002-06-30 17:57:21 +02:00
FIX_GCC_LINKING_PROBLEM