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
31
31
#define MYSQL_CLIENT
32
32
#undef MYSQL_SERVER
34
#include <my_global.h>
39
#include <my_getopt.h>
33
#include <libdrizzle/my_time.h>
34
#include <drizzled/global.h>
35
#include <mysys/my_sys.h>
36
#include <mystrings/m_string.h>
37
#include <libdrizzle/drizzle.h>
38
#include <libdrizzle/errmsg.h>
39
#include <mysys/my_getopt.h>
40
40
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
41
#include "mysql_priv.h"
42
#include "log_event.h"
43
#include "sql_common.h"
41
#include <drizzled/mysql_priv.h>
42
#include <drizzled/log_event.h>
43
#include <libdrizzle/sql_common.h>
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
static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
75
static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
74
static void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
75
static void warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
77
77
static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
78
78
static bool opt_hexdump= 0;
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));
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;
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.",
1000
1000
(char**) &start_position, (char**) &start_position, 0, GET_ULL,
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
(uint64_t)(~(uint32)0), 0, 0, 0},
1004
{"protocol", OPT_MYSQL_PROTOCOL,
1003
(uint64_t)(~(uint32_t)0), 0, 0, 0},
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,
1039
1039
(char**) &start_position, (char**) &start_position, 0, GET_ULL,
1040
1040
REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE,
1041
1041
/* COM_BINLOG_DUMP accepts only 4 bytes for the position */
1042
(uint64_t)(~(uint32)0), 0, 0, 0},
1042
(uint64_t)(~(uint32_t)0), 0, 0, 0},
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
1164
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");
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");
1172
1169
printf("Usage: %s [options] log-files\n", my_progname);
1173
1170
my_print_help(my_long_options);
1174
1171
my_print_variables(my_long_options);
1192
1189
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?).
1190
the next existing day, like in drizzled. Maybe this could be changed when
1191
drizzled is changed too (with its "strict" mode?).
1197
1194
my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap);
1200
#include <help_end.h>
1202
1197
extern "C" bool
1203
1198
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
1206
1201
bool tty_password=0;
1207
1202
switch (optid) {
1287
1282
static Exit_status safe_connect()
1289
mysql= mysql_init(NULL);
1284
drizzle= drizzle_create(NULL);
1293
error("Failed on mysql_init.");
1288
error("Failed on drizzle_create.");
1294
1289
return ERROR_STOP;
1297
1292
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))
1293
drizzle_options(drizzle, DRIZZLE_OPT_PROTOCOL, (char*) &opt_protocol);
1294
if (!drizzle_connect(drizzle, host, user, pass, 0, port, sock, 0))
1301
error("Failed on connect: %s", mysql_error(mysql));
1296
error("Failed on connect: %s", drizzle_error(drizzle));
1302
1297
return ERROR_STOP;
1304
mysql->reconnect= 1;
1299
drizzle->reconnect= 1;
1305
1300
return OK_CONTINUE;
1356
1351
static Exit_status check_master_version()
1353
DRIZZLE_RES* res = 0;
1360
1355
const char* version;
1362
if (mysql_query(mysql, "SELECT VERSION()") ||
1363
!(res = mysql_store_result(mysql)))
1357
if (drizzle_query(drizzle, "SELECT VERSION()") ||
1358
!(res = drizzle_store_result(drizzle)))
1365
1360
error("Could not find server version: "
1366
"Query failed when checking master version: %s", mysql_error(mysql));
1361
"Query failed when checking master version: %s", drizzle_error(drizzle));
1367
1362
return ERROR_STOP;
1369
if (!(row = mysql_fetch_row(res)))
1364
if (!(row = drizzle_fetch_row(res)))
1371
1366
error("Could not find server version: "
1372
1367
"Master returned no rows for SELECT VERSION().");
1453
1448
if ((retval= safe_connect()) != OK_CONTINUE)
1454
1449
return(retval);
1457
1452
if ((retval= check_master_version()) != OK_CONTINUE)
1458
1453
return(retval);
1461
1456
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
1464
int4store(buf, (uint32)start_position);
1459
int4store(buf, (uint32_t)start_position);
1465
1460
int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags);
1467
1462
size_t tlen = strlen(logname);
1468
if (tlen > UINT_MAX)
1463
if (tlen > UINT_MAX)
1470
1465
error("Log name too long.");
1471
1466
return(ERROR_STOP);
1473
1468
logname_len = (uint) tlen;
1474
1469
int4store(buf + 6, 0);
1475
1470
memcpy(buf + 10, logname, logname_len);
1476
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))
1478
1473
error("Got fatal error sending the log dump command.");
1479
1474
return(ERROR_STOP);
1499
1494
error("Could not construct log event object: %s", error_msg);
1500
1495
return(ERROR_STOP);
1503
1498
If reading from a remote host, ensure the temp_buf for the
1504
1499
Log_event class is pointing to the incoming stream.
1506
1501
if (remote_opt)
1507
ev->register_temp_buf((char*) net->read_pos + 1);
1502
ev->register_temp_buf((char*) net->read_pos + 1);
1509
1504
Log_event_type type= ev->get_type_code();
1510
1505
if (glob_description_event->binlog_version >= 3 ||
1719
1714
/* This is 5.0 */
1720
1715
Format_description_log_event *new_description_event;
1721
1716
my_b_seek(file, tmp_pos); /* seek back to event's start */
1722
if (!(new_description_event= (Format_description_log_event*)
1717
if (!(new_description_event= (Format_description_log_event*)
1723
1718
Log_event::read_log_event(file, glob_description_event)))
1724
1719
/* EOF can't be hit here normally, so it's a real error */
1812
1807
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)))
1808
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
1815
1810
error("Failed to init IO cache.");
1816
1811
return ERROR_STOP;
1824
1819
my_off_t length,tmp;
1825
1820
for (length= start_position_mot ; length > 0 ; length-=tmp)
1827
tmp=min(length,sizeof(buff));
1828
if (my_b_read(file, buff, (uint) tmp))
1822
tmp=min(length,sizeof(buff));
1823
if (my_b_read(file, buff, (uint) tmp))
1830
1825
error("Failed reading from file.");
1928
1923
load_processor.init_by_cur_dir();
1930
1925
fprintf(result_file,
1931
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1926
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
1933
1928
if (disable_log_bin)
1934
1929
fprintf(result_file,
1935
1930
"/*!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
1933
In drizzlebinlog|drizzle, don't want Drizzle to be disconnected after each
1939
1934
transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
1941
1936
fprintf(result_file,
1946
1941
fprintf(result_file,
1947
1942
"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
1948
1943
"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
1949
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1944
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
1950
1945
"\n/*!40101 SET NAMES %s */;\n", charset);
1952
1947
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;