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},
1167
1167
and you are welcome to modify and redistribute it under the GPL license\n");
1170
Dumps a MySQL binary log in a format usable for viewing or for piping to\n\
1171
the mysql command line client\n\n");
1170
Dumps a DRIZZLE binary log in a format usable for viewing or for piping to\n\
1171
the Drizzle command line client\n\n");
1172
1172
printf("Usage: %s [options] log-files\n", my_progname);
1173
1173
my_print_help(my_long_options);
1174
1174
my_print_variables(my_long_options);
1192
1192
Note that Feb 30th, Apr 31st cause no error messages and are mapped to
1193
the next existing day, like in mysqld. Maybe this could be changed when
1194
mysqld is changed too (with its "strict" mode?).
1193
the next existing day, like in drizzled. Maybe this could be changed when
1194
drizzled is changed too (with its "strict" mode?).
1197
1197
my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
1214
1214
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
1215
1215
char *start=argument;
1216
1216
pass= my_strdup(argument,MYF(MY_FAE));
1217
while (*argument) *argument++= 'x'; /* Destroy argument */
1217
while (*argument) *argument++= 'x'; /* Destroy argument */
1219
start[1]=0; /* Cut length of argument */
1219
start[1]=0; /* Cut length of argument */
1222
1222
tty_password=1;
1281
Create and initialize the global mysql object, and connect to the
1281
Create and initialize the global drizzle object, and connect to the
1284
1284
@retval ERROR_STOP An error occurred - the program should terminate.
1287
1287
static Exit_status safe_connect()
1289
mysql= mysql_init(NULL);
1289
drizzle= drizzle_init(NULL);
1293
error("Failed on mysql_init.");
1293
error("Failed on drizzle_init.");
1294
1294
return ERROR_STOP;
1297
1297
if (opt_protocol)
1298
mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
1299
if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
1298
drizzle_options(drizzle, DRIZZLE_OPT_PROTOCOL, (char*) &opt_protocol);
1299
if (!drizzle_connect(drizzle, host, user, pass, 0, port, sock, 0))
1301
error("Failed on connect: %s", mysql_error(mysql));
1301
error("Failed on connect: %s", drizzle_error(drizzle));
1302
1302
return ERROR_STOP;
1304
mysql->reconnect= 1;
1304
drizzle->reconnect= 1;
1305
1305
return OK_CONTINUE;
1347
1347
When reading a remote binlog, this function is used to grab the
1348
1348
Format_description_log_event in the beginning of the stream.
1350
1350
This is not as smart as check_header() (used for local log); it will
1351
1351
not work for a binlog which mixes format. TODO: fix this.
1356
1356
static Exit_status check_master_version()
1358
DRIZZLE_RES* res = 0;
1360
1360
const char* version;
1362
if (mysql_query(mysql, "SELECT VERSION()") ||
1363
!(res = mysql_store_result(mysql)))
1362
if (drizzle_query(drizzle, "SELECT VERSION()") ||
1363
!(res = drizzle_store_result(drizzle)))
1365
1365
error("Could not find server version: "
1366
"Query failed when checking master version: %s", mysql_error(mysql));
1366
"Query failed when checking master version: %s", drizzle_error(drizzle));
1367
1367
return ERROR_STOP;
1369
if (!(row = mysql_fetch_row(res)))
1369
if (!(row = drizzle_fetch_row(res)))
1371
1371
error("Could not find server version: "
1372
1372
"Master returned no rows for SELECT VERSION().");
1402
1402
glob_description_event= NULL;
1403
1403
error("Could not find server version: "
1404
"Master reported unrecognized MySQL version '%s'.", version);
1404
"Master reported unrecognized Drizzle version '%s'.", version);
1407
1407
if (!glob_description_event || !glob_description_event->is_valid())
1473
1473
logname_len = (uint) tlen;
1474
1474
int4store(buf + 6, 0);
1475
1475
memcpy(buf + 10, logname, logname_len);
1476
if (simple_command(mysql, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
1476
if (simple_command(drizzle, COM_BINLOG_DUMP, buf, logname_len + 10, 1))
1478
1478
error("Got fatal error sending the log dump command.");
1479
1479
return(ERROR_STOP);
1484
1484
const char *error_msg;
1487
len= cli_safe_read(mysql);
1487
len= cli_safe_read(drizzle);
1488
1488
if (len == packet_error)
1490
error("Got error reading packet from server: %s", mysql_error(mysql));
1490
error("Got error reading packet from server: %s", drizzle_error(drizzle));
1491
1491
return(ERROR_STOP);
1493
1493
if (len < 8 && net->read_pos[0] == 254)
1499
1499
error("Could not construct log event object: %s", error_msg);
1500
1500
return(ERROR_STOP);
1503
1503
If reading from a remote host, ensure the temp_buf for the
1504
1504
Log_event class is pointing to the incoming stream.
1506
1506
if (remote_opt)
1507
ev->register_temp_buf((char*) net->read_pos + 1);
1507
ev->register_temp_buf((char*) net->read_pos + 1);
1509
1509
Log_event_type type= ev->get_type_code();
1510
1510
if (glob_description_event->binlog_version >= 3 ||
1698
1698
if (buf[EVENT_TYPE_OFFSET] == START_EVENT_V3)
1700
1700
/* This is 3.23 or 4.x */
1701
if (uint4korr(buf + EVENT_LEN_OFFSET) <
1701
if (uint4korr(buf + EVENT_LEN_OFFSET) <
1702
1702
(LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
1704
1704
/* This is 3.23 (format 1) */
1719
1719
/* This is 5.0 */
1720
1720
Format_description_log_event *new_description_event;
1721
1721
my_b_seek(file, tmp_pos); /* seek back to event's start */
1722
if (!(new_description_event= (Format_description_log_event*)
1722
if (!(new_description_event= (Format_description_log_event*)
1723
1723
Log_event::read_log_event(file, glob_description_event)))
1724
1724
/* EOF can't be hit here normally, so it's a real error */
1799
1799
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
1800
1800
return ERROR_STOP;
1801
1801
if (init_io_cache(file, fd, 0, READ_CACHE, start_position_mot, 0,
1802
MYF(MY_WME | MY_NABP)))
1802
MYF(MY_WME | MY_NABP)))
1804
1804
my_close(fd, MYF(MY_WME));
1805
1805
return ERROR_STOP;
1812
1812
if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
1813
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1813
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1815
1815
error("Failed to init IO cache.");
1816
1816
return ERROR_STOP;
1824
1824
my_off_t length,tmp;
1825
1825
for (length= start_position_mot ; length > 0 ; length-=tmp)
1827
tmp=min(length,sizeof(buff));
1828
if (my_b_read(file, buff, (uint) tmp))
1827
tmp=min(length,sizeof(buff));
1828
if (my_b_read(file, buff, (uint) tmp))
1830
1830
error("Failed reading from file.");
1928
1928
load_processor.init_by_cur_dir();
1930
1930
fprintf(result_file,
1931
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1931
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1933
1933
if (disable_log_bin)
1934
1934
fprintf(result_file,
1935
1935
"/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
1938
In mysqlbinlog|mysql, don't want mysql to be disconnected after each
1938
In drizzlebinlog|drizzle, don't want Drizzle to be disconnected after each
1939
1939
transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
1941
1941
fprintf(result_file,
1946
1946
fprintf(result_file,
1947
1947
"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
1948
1948
"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
1949
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1949
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1950
1950
"\n/*!40101 SET NAMES %s */;\n", charset);
1952
1952
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
1966
1966
of transaction.
1968
1968
fprintf(result_file,
1969
"# End of log file\nROLLBACK /* added by mysqlbinlog */;\n"
1969
"# End of log file\nROLLBACK /* added by drizzlebinlog */;\n"
1970
1970
"/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
1971
1971
if (disable_log_bin)
1972
1972
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");