1
/* Copyright (C) 2001-2004 MySQL AB
1
/* Copyright (C) 2001-2004 DRIZZLE AB
3
3
This program is free software; you can redistribute it and/or modify
4
4
it under the terms of the GNU General Public License as published by
13
13
along with this program; if not, write to the Free Software
14
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
18
TODO: print the catalog (some USE catalog.db ????).
20
Standalone program to read a MySQL binary log (or relay log);
21
can read files produced by 3.23, 4.x, 5.0 servers.
20
Standalone program to read a Drizzle binary log (or relay log);
21
can read files produced by 3.23, 4.x, 5.0 servers.
23
23
Can read binlogs from 3.23/4.x/5.0 and relay logs from 4.x/5.0.
24
24
Should be able to read any file of these categories, even with
46
46
enum options_drizzlebinlog
48
48
OPT_CHARSETS_DIR=256, OPT_BASE64_OUTPUT_MODE,
49
OPT_DEBUG_CHECK, OPT_DEBUG_INFO, OPT_MYSQL_PROTOCOL,
49
OPT_DEBUG_CHECK, OPT_DEBUG_INFO, OPT_DRIZZLE_PROTOCOL,
50
50
OPT_SERVER_ID, OPT_SET_CHARSET, OPT_START_DATETIME,
51
51
OPT_START_POSITION, OPT_STOP_DATETIME, OPT_STOP_POSITION,
52
52
OPT_OPEN_FILES_LIMIT
55
#define BIN_LOG_HEADER_SIZE 4
56
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
59
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
55
#define BIN_LOG_HEADER_SIZE 4
56
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
59
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
61
61
char server_version[SERVER_VERSION_LENGTH];
62
62
ulong server_id = 0;
64
64
// needed by net_serv.c
65
65
ulong bytes_sent = 0L, bytes_received = 0L;
66
ulong mysqld_net_retry_count = 10L;
66
ulong drizzled_net_retry_count = 10L;
67
67
ulong open_files_limit;
69
69
static uint opt_protocol= 0;
70
70
static FILE *result_file;
72
static const char *load_default_groups[]= { "mysqlbinlog","client",0 };
72
static const char *load_default_groups[]= { "drizzlebinlog","client",0 };
74
74
static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
75
75
static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
102
102
static char *start_datetime_str, *stop_datetime_str;
103
103
static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX;
104
104
static uint64_t rec_count= 0;
105
static short binlog_flags = 0;
106
static MYSQL* mysql = NULL;
105
static short binlog_flags = 0;
106
static DRIZZLE *drizzle= NULL;
107
107
static const char* dirname_for_local_load= 0;
184
184
/* If we have to try more than 1000 times, something is seriously wrong */
185
185
for (uint version= 0; version<1000; version++)
187
sprintf(file_name_end,"-%x",version);
188
if ((res= my_create(filename,0,
189
O_CREAT|O_EXCL|O_BINARY|O_WRONLY,MYF(0)))!=-1)
187
sprintf(file_name_end,"-%x",version);
188
if ((res= my_create(filename,0,
189
O_CREAT|O_EXCL|O_BINARY|O_WRONLY,MYF(0)))!=-1)
201
201
return init_dynamic_array(&file_names, sizeof(File_name_record),
202
100,100 CALLER_INFO);
202
100,100 CALLER_INFO);
205
205
void init_by_dir_name(const char *dir)
207
207
target_dir_name_len= (convert_dirname(target_dir_name, dir, NullS) -
210
210
void init_by_cur_dir()
212
212
if (my_getwd(target_dir_name,sizeof(target_dir_name),MYF(MY_WME)))
214
214
target_dir_name_len= strlen(target_dir_name);
312
312
@return File handle >= 0 on success, -1 on error.
314
314
File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
321
321
fn_format(filename, le->fname, target_dir_name, "", MY_REPLACE_DIR);
322
322
len= strlen(filename);
323
323
tail= filename + len;
325
325
if ((file= create_unique_file(filename,tail)) < 0)
327
327
error("Could not construct local filename %s.",filename);
331
331
le->set_fname_outside_temp_buf(filename,len+strlen(tail));
374
374
return ERROR_STOP;
377
we just need to send something, as the server will read but
378
not examine the packet - this is because mysql_load() sends
379
an OK when it is done
377
we just need to send something, as the server will read but
378
not examine the packet - this is because drizzle_load() sends
379
an OK when it is done
385
385
error("Failed reading a packet during the dump of %s.", server_fname);
386
386
return ERROR_STOP;
389
389
if (packet_len > UINT_MAX)
391
391
error("Illegal length of packet read from net.");
392
392
return ERROR_STOP;
394
if (my_write(file, (uchar*) net->read_pos,
395
(uint) packet_len, MYF(MY_WME|MY_NABP)))
394
if (my_write(file, (uchar*) net->read_pos,
395
(uint) packet_len, MYF(MY_WME|MY_NABP)))
396
396
return ERROR_STOP;
399
399
return OK_CONTINUE;
553
553
Exit_status retval= OK_CONTINUE;
554
554
if (((file= my_open(fname,
555
O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
555
O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
557
557
error("Failed opening file %s", fname);
558
558
return(ERROR_STOP);
588
588
Replace windows-style backslashes by forward slashes so it can be
589
consumed by the mysql client, which requires Unix path.
589
consumed by the drizzle client, which requires Unix path.
591
591
@todo This is only useful under windows, so may be ifdef'ed out on
592
592
other systems. /Sven
757
757
if (shall_skip_database(ce->db))
758
758
goto end; // Next event
760
We print the event, but with a leading '#': this is just to inform
761
the user of the original command; the command we want to execute
762
will be a derivation of this original command (we will change the
763
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
760
We print the event, but with a leading '#': this is just to inform
761
the user of the original command; the command we want to execute
762
will be a derivation of this original command (we will change the
763
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
766
766
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
805
805
Execute_load_log_event *exv= (Execute_load_log_event*)ev;
806
806
Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
808
if ce is 0, it probably means that we have not seen the Create_file
809
event (a bad binlog, or most probably --start-position is after the
810
Create_file event). Print a warning comment.
808
if ce is 0, it probably means that we have not seen the Create_file
809
event (a bad binlog, or most probably --start-position is after the
810
Create_file event). Print a warning comment.
816
816
my_open() in Load_log_processor::append().
818
818
convert_path_to_forward_slashes((char*) ce->fname);
819
ce->print(result_file, print_event_info, true);
820
my_free((char*)ce->fname,MYF(MY_WME));
819
ce->print(result_file, print_event_info, true);
820
my_free((char*)ce->fname,MYF(MY_WME));
824
824
warning("Ignoring Execute_load_log_event as there is no "
843
843
(glob_description_event->flags & LOG_EVENT_BINLOG_IN_USE_F))
845
845
error("Attempting to dump binlog '%s', which was not closed properly. "
846
"Most probably, mysqld is still writing it, or it crashed. "
846
"Most probably, drizzled is still writing it, or it crashed. "
847
847
"Rerun with --force-if-open to ignore this problem.", logname);
848
848
return(ERROR_STOP);
946
946
(char**) &opt_base64_output_mode_str,
947
947
0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
949
mysqlbinlog needs charsets knowledge, to be able to convert a charset
949
drizzlebinlog needs charsets knowledge, to be able to convert a charset
950
950
number found in binlog to a charset name (to be able to print things
952
952
SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`;
964
964
(char**) &debug_info_flag, (char**) &debug_info_flag,
965
965
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
966
966
{"disable-log-bin", 'D', "Disable binary log. This is useful, if you "
967
"enabled --to-last-log and are sending the output to the same MySQL server. "
967
"enabled --to-last-log and are sending the output to the same DRIZZLE server. "
968
968
"This way you could avoid an endless loop. You would also like to use it "
969
969
"when restoring after a crash to avoid duplication of the statements you "
970
970
"already have. NOTE: you will need a SUPER privilege to use this option.",
1001
1001
REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
1002
1002
/* COM_BINLOG_DUMP accepts only 4 bytes for the position */
1003
1003
(uint64_t)(~(uint32_t)0), 0, 0, 0},
1004
{"protocol", OPT_MYSQL_PROTOCOL,
1004
{"protocol", OPT_DRIZZLE_PROTOCOL,
1005
1005
"The protocol of connection (tcp,socket,pipe,memory).",
1006
1006
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1007
{"read-from-remote-server", 'R', "Read binary logs from a MySQL server",
1007
{"read-from-remote-server", 'R', "Read binary logs from a Drizzle server",
1008
1008
(char**) &remote_opt, (char**) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1010
1010
{"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR,
1023
1023
(char**) &short_form, (char**) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
1025
1025
{"socket", 'S', "Socket file to use for connection.",
1026
(char**) &sock, (char**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
1026
(char**) &sock, (char**) &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
1028
1028
{"start-datetime", OPT_START_DATETIME,
1029
1029
"Start reading the binlog at first event having a datetime equal or "
1030
1030
"posterior to the argument; the argument must be a date and time "
1031
"in the local time zone, in any format accepted by the MySQL server "
1031
"in the local time zone, in any format accepted by the Drizzle server "
1032
1032
"for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1033
1033
"(you should probably use quotes for your shell to set it properly).",
1034
1034
(char**) &start_datetime_str, (char**) &start_datetime_str,
1043
1043
{"stop-datetime", OPT_STOP_DATETIME,
1044
1044
"Stop reading the binlog at first event having a datetime equal or "
1045
1045
"posterior to the argument; the argument must be a date and time "
1046
"in the local time zone, in any format accepted by the MySQL server "
1046
"in the local time zone, in any format accepted by the Drizzle server "
1047
1047
"for DATETIME and TIMESTAMP types, for example: 2004-12-25 11:25:56 "
1048
1048
"(you should probably use quotes for your shell to set it properly).",
1049
1049
(char**) &stop_datetime_str, (char**) &stop_datetime_str,
1056
1056
(uint64_t)(~(my_off_t)0), 0, 0, 0},
1057
1057
{"to-last-log", 't', "Requires -R. Will not stop at the end of the \
1058
1058
requested binlog but rather continue printing until the end of the last \
1059
binlog of the MySQL server. If you send the output to the same MySQL server, \
1059
binlog of the DRIZZLE server. If you send the output to the same DRIZZLE server, \
1060
1060
that may lead to an endless loop.",
1061
1061
(char**) &to_last_remote_log, (char**) &to_last_remote_log, 0, GET_BOOL,
1062
1062
NO_ARG, 0, 0, 0, 0, 0, 0},
1164
1164
and you are welcome to modify and redistribute it under the GPL license\n");
1167
Dumps a MySQL binary log in a format usable for viewing or for piping to\n\
1168
the mysql command line client\n\n");
1167
Dumps a DRIZZLE binary log in a format usable for viewing or for piping to\n\
1168
the Drizzle command line client\n\n");
1169
1169
printf("Usage: %s [options] log-files\n", my_progname);
1170
1170
my_print_help(my_long_options);
1171
1171
my_print_variables(my_long_options);
1189
1189
Note that Feb 30th, Apr 31st cause no error messages and are mapped to
1190
the next existing day, like in mysqld. Maybe this could be changed when
1191
mysqld is changed too (with its "strict" mode?).
1190
the next existing day, like in drizzled. Maybe this could be changed when
1191
drizzled is changed too (with its "strict" mode?).
1194
1194
my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
1209
1209
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1210
1210
char *start=argument;
1211
1211
pass= my_strdup(argument,MYF(MY_FAE));
1212
while (*argument) *argument++= 'x'; /* Destroy argument */
1212
while (*argument) *argument++= 'x'; /* Destroy argument */
1214
start[1]=0; /* Cut length of argument */
1214
start[1]=0; /* Cut length of argument */
1217
1217
tty_password=1;
1276
Create and initialize the global mysql object, and connect to the
1276
Create and initialize the global drizzle object, and connect to the
1279
1279
@retval ERROR_STOP An error occurred - the program should terminate.
1282
1282
static Exit_status safe_connect()
1284
mysql= mysql_init(NULL);
1284
drizzle= drizzle_create(NULL);
1288
error("Failed on mysql_init.");
1288
error("Failed on drizzle_create.");
1289
1289
return ERROR_STOP;
1292
1292
if (opt_protocol)
1293
mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
1294
if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
1293
drizzle_options(drizzle, DRIZZLE_OPT_PROTOCOL, (char*) &opt_protocol);
1294
if (!drizzle_connect(drizzle, host, user, pass, 0, port, sock, 0))
1296
error("Failed on connect: %s", mysql_error(mysql));
1296
error("Failed on connect: %s", drizzle_error(drizzle));
1297
1297
return ERROR_STOP;
1299
mysql->reconnect= 1;
1299
drizzle->reconnect= 1;
1300
1300
return OK_CONTINUE;
1342
1342
When reading a remote binlog, this function is used to grab the
1343
1343
Format_description_log_event in the beginning of the stream.
1345
1345
This is not as smart as check_header() (used for local log); it will
1346
1346
not work for a binlog which mixes format. TODO: fix this.
1351
1351
static Exit_status check_master_version()
1353
DRIZZLE_RES* res = 0;
1355
1355
const char* version;
1357
if (mysql_query(mysql, "SELECT VERSION()") ||
1358
!(res = mysql_store_result(mysql)))
1357
if (drizzle_query(drizzle, "SELECT VERSION()") ||
1358
!(res = drizzle_store_result(drizzle)))
1360
1360
error("Could not find server version: "
1361
"Query failed when checking master version: %s", mysql_error(mysql));
1361
"Query failed when checking master version: %s", drizzle_error(drizzle));
1362
1362
return ERROR_STOP;
1364
if (!(row = mysql_fetch_row(res)))
1364
if (!(row = drizzle_fetch_row(res)))
1366
1366
error("Could not find server version: "
1367
1367
"Master returned no rows for SELECT VERSION().");
1397
1397
glob_description_event= NULL;
1398
1398
error("Could not find server version: "
1399
"Master reported unrecognized MySQL version '%s'.", version);
1399
"Master reported unrecognized Drizzle version '%s'.", version);
1402
1402
if (!glob_description_event || !glob_description_event->is_valid())
1468
1468
logname_len = (uint) tlen;
1469
1469
int4store(buf + 6, 0);
1470
1470
memcpy(buf + 10, logname, logname_len);
1471
if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
1471
if (simple_command(drizzle, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
1473
1473
error("Got fatal error sending the log dump command.");
1474
1474
return(ERROR_STOP);
1479
1479
const char *error_msg;
1482
len= cli_safe_read(mysql);
1482
len= cli_safe_read(drizzle);
1483
1483
if (len == packet_error)
1485
error("Got error reading packet from server: %s", mysql_error(mysql));
1485
error("Got error reading packet from server: %s", drizzle_error(drizzle));
1486
1486
return(ERROR_STOP);
1488
1488
if (len < 8 && net->read_pos[0] == 254)
1494
1494
error("Could not construct log event object: %s", error_msg);
1495
1495
return(ERROR_STOP);
1498
1498
If reading from a remote host, ensure the temp_buf for the
1499
1499
Log_event class is pointing to the incoming stream.
1501
1501
if (remote_opt)
1502
ev->register_temp_buf((char*) net->read_pos + 1);
1502
ev->register_temp_buf((char*) net->read_pos + 1);
1504
1504
Log_event_type type= ev->get_type_code();
1505
1505
if (glob_description_event->binlog_version >= 3 ||
1693
1693
if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
1695
1695
/* This is 3.23 or 4.x */
1696
if (uint4korr(buf + EVENT_LEN_OFFSET) <
1696
if (uint4korr(buf + EVENT_LEN_OFFSET) <
1697
1697
(LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
1699
1699
/* This is 3.23 (format 1) */
1714
1714
/* This is 5.0 */
1715
1715
Format_description_log_event *new_description_event;
1716
1716
my_b_seek(file, tmp_pos); /* seek back to event's start */
1717
if (!(new_description_event= (Format_description_log_event*)
1717
if (!(new_description_event= (Format_description_log_event*)
1718
1718
Log_event::read_log_event(file, glob_description_event)))
1719
1719
/* EOF can't be hit here normally, so it's a real error */
1794
1794
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
1795
1795
return ERROR_STOP;
1796
1796
if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
1797
MYF(MY_WME | MY_NABP)))
1797
MYF(MY_WME | MY_NABP)))
1799
1799
my_close(fd, MYF(MY_WME));
1800
1800
return ERROR_STOP;
1807
1807
if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
1808
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1808
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1810
1810
error("Failed to init IO cache.");
1811
1811
return ERROR_STOP;
1819
1819
my_off_t length,tmp;
1820
1820
for (length= start_position_mot ; length > 0 ; length-=tmp)
1822
tmp=min(length,sizeof(buff));
1823
if (my_b_read(file, buff, (uint) tmp))
1822
tmp=min(length,sizeof(buff));
1823
if (my_b_read(file, buff, (uint) tmp))
1825
1825
error("Failed reading from file.");
1923
1923
load_processor.init_by_cur_dir();
1925
1925
fprintf(result_file,
1926
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1926
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1928
1928
if (disable_log_bin)
1929
1929
fprintf(result_file,
1930
1930
"/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
1933
In mysqlbinlog|mysql, don't want mysql to be disconnected after each
1933
In drizzlebinlog|drizzle, don't want Drizzle to be disconnected after each
1934
1934
transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
1936
1936
fprintf(result_file,
1941
1941
fprintf(result_file,
1942
1942
"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
1943
1943
"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
1944
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1944
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1945
1945
"\n/*!40101 SET NAMES %s */;\n", charset);
1947
1947
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
1961
1961
of transaction.
1963
1963
fprintf(result_file,
1964
"# End of log file\nROLLBACK /* added by mysqlbinlog */;\n"
1964
"# End of log file\nROLLBACK /* added by drizzlebinlog */;\n"
1965
1965
"/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
1966
1966
if (disable_log_bin)
1967
1967
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");