Commit e762328b authored by mats@romeo.(none)'s avatar mats@romeo.(none)

BUG#19459 (BINLOG RBR command does not lock tables correctly causing

crash for, e.g., NDB):

Before, mysqlbinlog printed table map events as a separate statement, so
when executing the event, the opened table was subsequently closed
when the statement ended. Instead, the row-based events that make up
a statement are now printed as *one* BINLOG statement, which means
that the table maps and the following *_rows_log_event events are
executed fully before the statement ends.

Changing implementation of BINLOG statement to be able to read the 
emitted format, which now consists of several chunks of BASE64-encoded
data.
parent d1b96862
...@@ -475,6 +475,30 @@ static bool check_database(const char *log_dbname) ...@@ -475,6 +475,30 @@ static bool check_database(const char *log_dbname)
} }
static int
write_event_header_and_base64(Log_event *ev, FILE *result_file,
PRINT_EVENT_INFO *print_event_info)
{
DBUG_ENTER("write_event_header_and_base64");
/* Write header and base64 output to cache */
IO_CACHE result_cache;
if (init_io_cache(&result_cache, -1, 0, WRITE_CACHE, 0L, FALSE,
MYF(MY_WME | MY_NABP)))
{
return 1;
}
ev->print_header(&result_cache, print_event_info, FALSE);
ev->print_base64(&result_cache, print_event_info, FALSE);
/* Read data from cache and write to result file */
my_b_copy_to_file(&result_cache, result_file);
end_io_cache(&result_cache);
DBUG_RETURN(0);
}
/* /*
Process an event Process an event
...@@ -537,18 +561,18 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ...@@ -537,18 +561,18 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
print_event_info->base64_output= opt_base64_output; print_event_info->base64_output= opt_base64_output;
DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str()));
switch (ev_type) { switch (ev_type) {
case QUERY_EVENT: case QUERY_EVENT:
if (check_database(((Query_log_event*)ev)->db)) if (check_database(((Query_log_event*)ev)->db))
goto end; goto end;
if (opt_base64_output) if (opt_base64_output)
{ write_event_header_and_base64(ev, result_file, print_event_info);
ev->print_header(result_file, print_event_info);
ev->print_base64(result_file, print_event_info);
}
else else
ev->print(result_file, print_event_info); ev->print(result_file, print_event_info);
break; break;
case CREATE_FILE_EVENT: case CREATE_FILE_EVENT:
{ {
Create_file_log_event* ce= (Create_file_log_event*)ev; Create_file_log_event* ce= (Create_file_log_event*)ev;
...@@ -569,8 +593,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ...@@ -569,8 +593,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
*/ */
if (opt_base64_output) if (opt_base64_output)
{ {
ce->print_header(result_file, print_event_info); write_event_header_and_base64(ce, result_file, print_event_info);
ce->print_base64(result_file, print_event_info);
} }
else else
ce->print(result_file, print_event_info, TRUE); ce->print(result_file, print_event_info, TRUE);
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
Copy contents of an IO_CACHE to a file. Copy contents of an IO_CACHE to a file.
SYNOPSIS SYNOPSIS
copy_io_cache_to_file() my_b_copy_to_file()
cache IO_CACHE to copy from cache IO_CACHE to copy from
file File to copy to file File to copy to
......
...@@ -31,32 +31,111 @@ ...@@ -31,32 +31,111 @@
#define log_cs &my_charset_latin1 #define log_cs &my_charset_latin1
/*
Cache that will automatically be written to a dedicated file on
destruction.
DESCRIPTION
*/
class Write_on_release_cache
{
public:
enum flag
{
FLUSH_F
};
typedef unsigned short flag_set;
/*
Constructor.
SYNOPSIS
Write_on_release_cache
cache Pointer to cache to use
file File to write cache to upon destruction
flags Flags for the cache
DESCRIPTION
Class used to guarantee copy of cache to file before exiting the
current block. On successful copy of the cache, the cache will
be reinited as a WRITE_CACHE.
Currently, a pointer to the cache is provided in the
constructor, but it would be possible to create a subclass
holding the IO_CACHE itself.
*/
Write_on_release_cache(IO_CACHE *cache, FILE *file, flag_set flags = 0)
: m_cache(cache), m_file(file), m_flags(flags)
{
reinit_io_cache(m_cache, WRITE_CACHE, 0L, FALSE, TRUE);
}
~Write_on_release_cache()
{
if (!my_b_copy_to_file(m_cache, m_file))
reinit_io_cache(m_cache, WRITE_CACHE, 0L, FALSE, TRUE);
if (m_flags | FLUSH_F)
fflush(m_file);
}
/*
Return a pointer to the internal IO_CACHE.
SYNOPSIS
operator&()
DESCRIPTION
Function to return a pointer to the internal, so that the object
can be treated as a IO_CACHE and used with the my_b_* IO_CACHE
functions
RETURN VALUE
A pointer to the internal IO_CACHE.
*/
IO_CACHE *operator&()
{
return m_cache;
}
private:
// Hidden, to prevent usage.
Write_on_release_cache(Write_on_release_cache const&);
IO_CACHE *m_cache;
FILE *m_file;
flag_set m_flags;
};
/* /*
pretty_print_str() pretty_print_str()
*/ */
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
static void pretty_print_str(FILE* file, char* str, int len) static void pretty_print_str(IO_CACHE* cache, char* str, int len)
{ {
char* end = str + len; char* end = str + len;
fputc('\'', file); my_b_printf(cache, "\'");
while (str < end) while (str < end)
{ {
char c; char c;
switch ((c=*str++)) { switch ((c=*str++)) {
case '\n': fprintf(file, "\\n"); break; case '\n': my_b_printf(cache, "\\n"); break;
case '\r': fprintf(file, "\\r"); break; case '\r': my_b_printf(cache, "\\r"); break;
case '\\': fprintf(file, "\\\\"); break; case '\\': my_b_printf(cache, "\\\\"); break;
case '\b': fprintf(file, "\\b"); break; case '\b': my_b_printf(cache, "\\b"); break;
case '\t': fprintf(file, "\\t"); break; case '\t': my_b_printf(cache, "\\t"); break;
case '\'': fprintf(file, "\\'"); break; case '\'': my_b_printf(cache, "\\'"); break;
case 0 : fprintf(file, "\\0"); break; case 0 : my_b_printf(cache, "\\0"); break;
default: default:
fputc(c, file); my_b_printf(cache, "%c", c);
break; break;
} }
} }
fputc('\'', file); my_b_printf(cache, "\'");
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -293,14 +372,15 @@ append_query_string(CHARSET_INFO *csinfo, ...@@ -293,14 +372,15 @@ append_query_string(CHARSET_INFO *csinfo,
*/ */
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
static void print_set_option(FILE* file, uint32 bits_changed, uint32 option, static void print_set_option(IO_CACHE* file, uint32 bits_changed,
uint32 flags, const char* name, bool* need_comma) uint32 option, uint32 flags, const char* name,
bool* need_comma)
{ {
if (bits_changed & option) if (bits_changed & option)
{ {
if (*need_comma) if (*need_comma)
fprintf(file,", "); my_b_printf(file,", ");
fprintf(file,"%s=%d", name, test(flags & option)); my_b_printf(file,"%s=%d", name, test(flags & option));
*need_comma= 1; *need_comma= 1;
} }
} }
...@@ -959,20 +1039,23 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, ...@@ -959,20 +1039,23 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
Log_event::print_header() Log_event::print_header()
*/ */
void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) void Log_event::print_header(IO_CACHE* file,
PRINT_EVENT_INFO* print_event_info,
bool is_more __attribute__((unused)))
{ {
char llbuff[22]; char llbuff[22];
my_off_t hexdump_from= print_event_info->hexdump_from; my_off_t hexdump_from= print_event_info->hexdump_from;
DBUG_ENTER("Log_event::print_header");
fputc('#', file); my_b_printf(file, "#");
print_timestamp(file); print_timestamp(file);
fprintf(file, " server id %d end_log_pos %s ", server_id, my_b_printf(file, " server id %d end_log_pos %s ", server_id,
llstr(log_pos,llbuff)); llstr(log_pos,llbuff));
/* mysqlbinlog --hexdump */ /* mysqlbinlog --hexdump */
if (print_event_info->hexdump_from) if (print_event_info->hexdump_from)
{ {
fprintf(file, "\n"); my_b_printf(file, "\n");
uchar *ptr= (uchar*)temp_buf; uchar *ptr= (uchar*)temp_buf;
my_off_t size= my_off_t size=
uint4korr(ptr + EVENT_LEN_OFFSET) - LOG_EVENT_MINIMAL_HEADER_LEN; uint4korr(ptr + EVENT_LEN_OFFSET) - LOG_EVENT_MINIMAL_HEADER_LEN;
...@@ -985,15 +1068,21 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -985,15 +1068,21 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
/* Pretty-print event common header if header is exactly 19 bytes */ /* Pretty-print event common header if header is exactly 19 bytes */
if (print_event_info->common_header_len == LOG_EVENT_MINIMAL_HEADER_LEN) if (print_event_info->common_header_len == LOG_EVENT_MINIMAL_HEADER_LEN)
{ {
fprintf(file, "# Position Timestamp Type Master ID " char emit_buf[256]; // Enough for storing one line
"Size Master Pos Flags \n"); my_b_printf(file, "# Position Timestamp Type Master ID "
fprintf(file, "# %8.8lx %02x %02x %02x %02x %02x " "Size Master Pos Flags \n");
"%02x %02x %02x %02x %02x %02x %02x %02x " int const bytes_written=
"%02x %02x %02x %02x %02x %02x\n", my_snprintf(emit_buf, sizeof(emit_buf),
(unsigned long) hexdump_from, "# %8.8lx %02x %02x %02x %02x %02x "
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], "%02x %02x %02x %02x %02x %02x %02x %02x "
ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], "%02x %02x %02x %02x %02x %02x\n",
ptr[14], ptr[15], ptr[16], ptr[17], ptr[18]); (unsigned long) hexdump_from,
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6],
ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13],
ptr[14], ptr[15], ptr[16], ptr[17], ptr[18]);
DBUG_ASSERT(bytes_written >= 0);
DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
my_b_write(file, emit_buf, bytes_written);
ptr += LOG_EVENT_MINIMAL_HEADER_LEN; ptr += LOG_EVENT_MINIMAL_HEADER_LEN;
hexdump_from += LOG_EVENT_MINIMAL_HEADER_LEN; hexdump_from += LOG_EVENT_MINIMAL_HEADER_LEN;
} }
...@@ -1010,9 +1099,21 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -1010,9 +1099,21 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
if (i % 16 == 15) if (i % 16 == 15)
{ {
fprintf(file, "# %8.8lx %-48.48s |%16s|\n", /*
(unsigned long) (hexdump_from + (i & 0xfffffff0)), my_b_printf() does not support full printf() formats, so we
hex_string, char_string); have to do it this way.
TODO: Rewrite my_b_printf() to support full printf() syntax.
*/
char emit_buf[256];
int const bytes_written=
my_snprintf(emit_buf, sizeof(emit_buf),
"# %8.8lx %-48.48s |%16s|\n",
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
DBUG_ASSERT(bytes_written >= 0);
DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
my_b_write(file, emit_buf, bytes_written);
hex_string[0]= 0; hex_string[0]= 0;
char_string[0]= 0; char_string[0]= 0;
c= char_string; c= char_string;
...@@ -1024,28 +1125,52 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -1024,28 +1125,52 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
/* Non-full last line */ /* Non-full last line */
if (hex_string[0]) if (hex_string[0])
fprintf(file, "# %8.8lx %-48.48s |%s|\n# ", {
(unsigned long) (hexdump_from + (i & 0xfffffff0)), char emit_buf[256];
hex_string, char_string); int const bytes_written=
my_snprintf(emit_buf, sizeof(emit_buf),
"# %8.8lx %-48.48s |%s|\n# ",
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
DBUG_ASSERT(bytes_written >= 0);
DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
my_b_write(file, emit_buf, bytes_written);
}
} }
DBUG_VOID_RETURN;
} }
void Log_event::print_base64(FILE* file, PRINT_EVENT_INFO* print_event_info) void Log_event::print_base64(IO_CACHE* file,
PRINT_EVENT_INFO* print_event_info,
bool more)
{ {
uchar *ptr= (uchar*)temp_buf; const uchar *ptr= (const uchar *)temp_buf;
my_off_t size= uint4korr(ptr + EVENT_LEN_OFFSET); my_off_t size= uint4korr(ptr + EVENT_LEN_OFFSET);
char *tmp_str= DBUG_ENTER("Log_event::print_base64");
(char *) my_malloc(base64_needed_encoded_length(size), MYF(MY_WME));
size_t const tmp_str_sz= base64_needed_encoded_length(size);
char *const tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME));
if (!tmp_str) { if (!tmp_str) {
fprintf(stderr, "\nError: Out of memory. " fprintf(stderr, "\nError: Out of memory. "
"Could not print correct binlog event.\n"); "Could not print correct binlog event.\n");
return; DBUG_VOID_RETURN;
} }
int res= base64_encode(ptr, size, tmp_str);
fprintf(file, "\nBINLOG '\n%s\n';\n", tmp_str); int const res= base64_encode(ptr, size, tmp_str);
DBUG_ASSERT(res == 0);
if (my_b_tell(file) == 0)
my_b_printf(file, "\nBINLOG '\n");
my_b_printf(file, "%s\n", tmp_str);
if (!more)
my_b_printf(file, "';\n");
my_free(tmp_str, MYF(0)); my_free(tmp_str, MYF(0));
DBUG_VOID_RETURN;
} }
...@@ -1053,9 +1178,10 @@ void Log_event::print_base64(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -1053,9 +1178,10 @@ void Log_event::print_base64(FILE* file, PRINT_EVENT_INFO* print_event_info)
Log_event::print_timestamp() Log_event::print_timestamp()
*/ */
void Log_event::print_timestamp(FILE* file, time_t* ts) void Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
{ {
struct tm *res; struct tm *res;
DBUG_ENTER("Log_event::print_timestamp");
if (!ts) if (!ts)
ts = &when; ts = &when;
#ifdef MYSQL_SERVER // This is always false #ifdef MYSQL_SERVER // This is always false
...@@ -1065,13 +1191,14 @@ void Log_event::print_timestamp(FILE* file, time_t* ts) ...@@ -1065,13 +1191,14 @@ void Log_event::print_timestamp(FILE* file, time_t* ts)
res=localtime(ts); res=localtime(ts);
#endif #endif
fprintf(file,"%02d%02d%02d %2d:%02d:%02d", my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
res->tm_year % 100, res->tm_year % 100,
res->tm_mon+1, res->tm_mon+1,
res->tm_mday, res->tm_mday,
res->tm_hour, res->tm_hour,
res->tm_min, res->tm_min,
res->tm_sec); res->tm_sec);
DBUG_VOID_RETURN;
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -1531,7 +1658,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, ...@@ -1531,7 +1658,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
*/ */
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Query_log_event::print_query_header(FILE* file, void Query_log_event::print_query_header(IO_CACHE* file,
PRINT_EVENT_INFO* print_event_info) PRINT_EVENT_INFO* print_event_info)
{ {
// TODO: print the catalog ?? // TODO: print the catalog ??
...@@ -1541,9 +1668,10 @@ void Query_log_event::print_query_header(FILE* file, ...@@ -1541,9 +1668,10 @@ void Query_log_event::print_query_header(FILE* file,
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
print_header(file, print_event_info); print_header(file, print_event_info, FALSE);
fprintf(file, "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n", my_b_printf(file, "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
get_type_str(), (ulong) thread_id, (ulong) exec_time, error_code); get_type_str(), (ulong) thread_id, (ulong) exec_time,
error_code);
} }
if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db) if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db)
...@@ -1551,15 +1679,15 @@ void Query_log_event::print_query_header(FILE* file, ...@@ -1551,15 +1679,15 @@ void Query_log_event::print_query_header(FILE* file,
if (different_db= memcmp(print_event_info->db, db, db_len + 1)) if (different_db= memcmp(print_event_info->db, db, db_len + 1))
memcpy(print_event_info->db, db, db_len + 1); memcpy(print_event_info->db, db, db_len + 1);
if (db[0] && different_db) if (db[0] && different_db)
fprintf(file, "use %s;\n", db); my_b_printf(file, "use %s;\n", db);
} }
end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10); end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
*end++=';'; *end++=';';
*end++='\n'; *end++='\n';
my_fwrite(file, (byte*) buff, (uint) (end-buff),MYF(MY_NABP | MY_WME)); my_b_write(file, (byte*) buff, (uint) (end-buff));
if (flags & LOG_EVENT_THREAD_SPECIFIC_F) if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
fprintf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id); my_b_printf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id);
/* /*
If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to
...@@ -1581,14 +1709,14 @@ void Query_log_event::print_query_header(FILE* file, ...@@ -1581,14 +1709,14 @@ void Query_log_event::print_query_header(FILE* file,
if (unlikely(tmp)) /* some bits have changed */ if (unlikely(tmp)) /* some bits have changed */
{ {
bool need_comma= 0; bool need_comma= 0;
fprintf(file, "SET "); my_b_printf(file, "SET ");
print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2, print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
"@@session.foreign_key_checks", &need_comma); "@@session.foreign_key_checks", &need_comma);
print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2, print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
"@@session.sql_auto_is_null", &need_comma); "@@session.sql_auto_is_null", &need_comma);
print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2, print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
"@@session.unique_checks", &need_comma); "@@session.unique_checks", &need_comma);
fprintf(file,";\n"); my_b_printf(file,";\n");
print_event_info->flags2= flags2; print_event_info->flags2= flags2;
} }
} }
...@@ -1616,14 +1744,14 @@ void Query_log_event::print_query_header(FILE* file, ...@@ -1616,14 +1744,14 @@ void Query_log_event::print_query_header(FILE* file,
} }
if (unlikely(print_event_info->sql_mode != sql_mode)) if (unlikely(print_event_info->sql_mode != sql_mode))
{ {
fprintf(file,"SET @@session.sql_mode=%lu;\n",(ulong)sql_mode); my_b_printf(file,"SET @@session.sql_mode=%lu;\n",(ulong)sql_mode);
print_event_info->sql_mode= sql_mode; print_event_info->sql_mode= sql_mode;
} }
} }
if (print_event_info->auto_increment_increment != auto_increment_increment || if (print_event_info->auto_increment_increment != auto_increment_increment ||
print_event_info->auto_increment_offset != auto_increment_offset) print_event_info->auto_increment_offset != auto_increment_offset)
{ {
fprintf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu;\n", my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu;\n",
auto_increment_increment,auto_increment_offset); auto_increment_increment,auto_increment_offset);
print_event_info->auto_increment_increment= auto_increment_increment; print_event_info->auto_increment_increment= auto_increment_increment;
print_event_info->auto_increment_offset= auto_increment_offset; print_event_info->auto_increment_offset= auto_increment_offset;
...@@ -1643,16 +1771,17 @@ void Query_log_event::print_query_header(FILE* file, ...@@ -1643,16 +1771,17 @@ void Query_log_event::print_query_header(FILE* file,
CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME)); CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME));
if (cs_info) if (cs_info)
{ {
fprintf(file, "/*!\\C %s */;\n", cs_info->csname); /* for mysql client */ /* for mysql client */
my_b_printf(file, "/*!\\C %s */;\n", cs_info->csname);
} }
fprintf(file,"SET " my_b_printf(file,"SET "
"@@session.character_set_client=%d," "@@session.character_set_client=%d,"
"@@session.collation_connection=%d," "@@session.collation_connection=%d,"
"@@session.collation_server=%d" "@@session.collation_server=%d"
";\n", ";\n",
uint2korr(charset), uint2korr(charset),
uint2korr(charset+2), uint2korr(charset+2),
uint2korr(charset+4)); uint2korr(charset+4));
memcpy(print_event_info->charset, charset, 6); memcpy(print_event_info->charset, charset, 6);
} }
} }
...@@ -1660,7 +1789,7 @@ void Query_log_event::print_query_header(FILE* file, ...@@ -1660,7 +1789,7 @@ void Query_log_event::print_query_header(FILE* file,
{ {
if (bcmp(print_event_info->time_zone_str, time_zone_str, time_zone_len+1)) if (bcmp(print_event_info->time_zone_str, time_zone_str, time_zone_len+1))
{ {
fprintf(file,"SET @@session.time_zone='%s';\n", time_zone_str); my_b_printf(file,"SET @@session.time_zone='%s';\n", time_zone_str);
memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1); memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
} }
} }
...@@ -1669,9 +1798,11 @@ void Query_log_event::print_query_header(FILE* file, ...@@ -1669,9 +1798,11 @@ void Query_log_event::print_query_header(FILE* file,
void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
print_query_header(file, print_event_info); Write_on_release_cache cache(&print_event_info->head_cache, file);
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
fputs(";\n", file); print_query_header(&cache, print_event_info);
my_b_write(&cache, (byte*) query, q_len);
my_b_printf(&cache, ";\n");
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -1971,18 +2102,23 @@ void Start_log_event_v3::pack_info(Protocol *protocol) ...@@ -1971,18 +2102,23 @@ void Start_log_event_v3::pack_info(Protocol *protocol)
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
DBUG_ENTER("Start_log_event_v3::print");
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, my_b_printf(&cache, "\tStart: binlog v %d, server v %s created ",
server_version); binlog_version, server_version);
print_timestamp(file); print_timestamp(&cache);
if (created) if (created)
fprintf(file," at startup"); my_b_printf(&cache," at startup");
fputc('\n', file); my_b_printf(&cache, "\n");
if (flags & LOG_EVENT_BINLOG_IN_USE_F) if (flags & LOG_EVENT_BINLOG_IN_USE_F)
fprintf(file, "# Warning: this binlog was not closed properly. " my_b_printf(&cache, "# Warning: this binlog was not closed properly. "
"Most probably mysqld crashed writing it.\n"); "Most probably mysqld crashed writing it.\n");
} }
if (!artificial_event && created) if (!artificial_event && created)
{ {
...@@ -1993,12 +2129,12 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -1993,12 +2129,12 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
and rollback unfinished transaction. and rollback unfinished transaction.
Probably this can be done with RESET CONNECTION (syntax to be defined). Probably this can be done with RESET CONNECTION (syntax to be defined).
*/ */
fprintf(file,"RESET CONNECTION;\n"); my_b_printf(&cache,"RESET CONNECTION;\n");
#else #else
fprintf(file,"ROLLBACK;\n"); my_b_printf(&cache,"ROLLBACK;\n");
#endif #endif
} }
fflush(file); DBUG_VOID_RETURN;
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -2722,15 +2858,17 @@ void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -2722,15 +2858,17 @@ void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
} }
void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info, void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
bool commented) bool commented)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
DBUG_ENTER("Load_log_event::print"); DBUG_ENTER("Load_log_event::print");
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tQuery\tthread_id=%ld\texec_time=%ld\n", my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
thread_id, exec_time); thread_id, exec_time);
} }
bool different_db= 1; bool different_db= 1;
...@@ -2748,65 +2886,65 @@ void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info, ...@@ -2748,65 +2886,65 @@ void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info,
} }
if (db && db[0] && different_db) if (db && db[0] && different_db)
fprintf(file, "%suse %s;\n", my_b_printf(&cache, "%suse %s;\n",
commented ? "# " : "", commented ? "# " : "",
db); db);
if (flags & LOG_EVENT_THREAD_SPECIFIC_F) if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
fprintf(file,"%sSET @@session.pseudo_thread_id=%lu;\n", my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu;\n",
commented ? "# " : "", (ulong)thread_id); commented ? "# " : "", (ulong)thread_id);
fprintf(file, "%sLOAD DATA ", my_b_printf(&cache, "%sLOAD DATA ",
commented ? "# " : ""); commented ? "# " : "");
if (check_fname_outside_temp_buf()) if (check_fname_outside_temp_buf())
fprintf(file, "LOCAL "); my_b_printf(&cache, "LOCAL ");
fprintf(file, "INFILE '%-*s' ", fname_len, fname); my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname);
if (sql_ex.opt_flags & REPLACE_FLAG) if (sql_ex.opt_flags & REPLACE_FLAG)
fprintf(file," REPLACE "); my_b_printf(&cache," REPLACE ");
else if (sql_ex.opt_flags & IGNORE_FLAG) else if (sql_ex.opt_flags & IGNORE_FLAG)
fprintf(file," IGNORE "); my_b_printf(&cache," IGNORE ");
fprintf(file, "INTO TABLE `%s`", table_name); my_b_printf(&cache, "INTO TABLE `%s`", table_name);
fprintf(file, " FIELDS TERMINATED BY "); my_b_printf(&cache, " FIELDS TERMINATED BY ");
pretty_print_str(file, sql_ex.field_term, sql_ex.field_term_len); pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len);
if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG) if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
fprintf(file," OPTIONALLY "); my_b_printf(&cache," OPTIONALLY ");
fprintf(file, " ENCLOSED BY "); my_b_printf(&cache, " ENCLOSED BY ");
pretty_print_str(file, sql_ex.enclosed, sql_ex.enclosed_len); pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len);
fprintf(file, " ESCAPED BY "); my_b_printf(&cache, " ESCAPED BY ");
pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len); pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len);
fprintf(file," LINES TERMINATED BY "); my_b_printf(&cache," LINES TERMINATED BY ");
pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len); pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len);
if (sql_ex.line_start) if (sql_ex.line_start)
{ {
fprintf(file," STARTING BY "); my_b_printf(&cache," STARTING BY ");
pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len); pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len);
} }
if ((long) skip_lines > 0) if ((long) skip_lines > 0)
fprintf(file, " IGNORE %ld LINES", (long) skip_lines); my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines);
if (num_fields) if (num_fields)
{ {
uint i; uint i;
const char* field = fields; const char* field = fields;
fprintf(file, " ("); my_b_printf(&cache, " (");
for (i = 0; i < num_fields; i++) for (i = 0; i < num_fields; i++)
{ {
if (i) if (i)
fputc(',', file); my_b_printf(&cache, ",");
fprintf(file, field); my_b_printf(&cache, field);
field += field_lens[i] + 1; field += field_lens[i] + 1;
} }
fputc(')', file); my_b_printf(&cache, ")");
} }
fprintf(file, ";\n"); my_b_printf(&cache, ";\n");
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -3139,17 +3277,16 @@ void Rotate_log_event::pack_info(Protocol *protocol) ...@@ -3139,17 +3277,16 @@ void Rotate_log_event::pack_info(Protocol *protocol)
void Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
char buf[22]; char buf[22];
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
if (print_event_info->short_form) if (print_event_info->short_form)
return; return;
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tRotate to "); my_b_printf(&cache, "\tRotate to ");
if (new_log_ident) if (new_log_ident)
my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, my_b_write(&cache, (byte*) new_log_ident, (uint)ident_len);
MYF(MY_NABP | MY_WME)); my_b_printf(&cache, " pos: %s\n", llstr(pos, buf));
fprintf(file, " pos: %s", llstr(pos, buf));
fputc('\n', file);
fflush(file);
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -3364,14 +3501,16 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -3364,14 +3501,16 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
char llbuff[22]; char llbuff[22];
const char *msg; const char *msg;
LINT_INIT(msg); LINT_INIT(msg);
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tIntvar\n"); my_b_printf(&cache, "\tIntvar\n");
} }
fprintf(file, "SET "); my_b_printf(&cache, "SET ");
switch (type) { switch (type) {
case LAST_INSERT_ID_EVENT: case LAST_INSERT_ID_EVENT:
msg="LAST_INSERT_ID"; msg="LAST_INSERT_ID";
...@@ -3384,8 +3523,7 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -3384,8 +3523,7 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
msg="INVALID_INT"; msg="INVALID_INT";
break; break;
} }
fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); my_b_printf(&cache, "%s=%s;\n", msg, llstr(val,llbuff));
fflush(file);
} }
#endif #endif
...@@ -3454,15 +3592,17 @@ bool Rand_log_event::write(IO_CACHE* file) ...@@ -3454,15 +3592,17 @@ bool Rand_log_event::write(IO_CACHE* file)
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
char llbuff[22],llbuff2[22]; char llbuff[22],llbuff2[22];
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tRand\n"); my_b_printf(&cache, "\tRand\n");
} }
fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n", my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
llstr(seed1, llbuff),llstr(seed2, llbuff2)); llstr(seed1, llbuff),llstr(seed2, llbuff2));
fflush(file);
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -3524,16 +3664,18 @@ bool Xid_log_event::write(IO_CACHE* file) ...@@ -3524,16 +3664,18 @@ bool Xid_log_event::write(IO_CACHE* file)
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
char buf[64]; char buf[64];
longlong10_to_str(xid, buf, 10); longlong10_to_str(xid, buf, 10);
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tXid = %s\n", buf); my_b_printf(&cache, "\tXid = %s\n", buf);
fflush(file);
} }
fprintf(file, "COMMIT;\n"); my_b_printf(&cache, "COMMIT;\n");
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -3723,19 +3865,22 @@ bool User_var_log_event::write(IO_CACHE* file) ...@@ -3723,19 +3865,22 @@ bool User_var_log_event::write(IO_CACHE* file)
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tUser_var\n"); my_b_printf(&cache, "\tUser_var\n");
} }
fprintf(file, "SET @`"); my_b_printf(&cache, "SET @`");
my_fwrite(file, (byte*) name, (uint) (name_len), MYF(MY_NABP | MY_WME)); my_b_write(&cache, (byte*) name, (uint) (name_len));
fprintf(file, "`"); my_b_printf(&cache, "`");
if (is_null) if (is_null)
{ {
fprintf(file, ":=NULL;\n"); my_b_printf(&cache, ":=NULL;\n");
} }
else else
{ {
...@@ -3743,12 +3888,12 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -3743,12 +3888,12 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
case REAL_RESULT: case REAL_RESULT:
double real_val; double real_val;
float8get(real_val, val); float8get(real_val, val);
fprintf(file, ":=%.14g;\n", real_val); my_b_printf(&cache, ":=%.14g;\n", real_val);
break; break;
case INT_RESULT: case INT_RESULT:
char int_buf[22]; char int_buf[22];
longlong10_to_str(uint8korr(val), int_buf, -10); longlong10_to_str(uint8korr(val), int_buf, -10);
fprintf(file, ":=%s;\n", int_buf); my_b_printf(&cache, ":=%s;\n", int_buf);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
...@@ -3764,7 +3909,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -3764,7 +3909,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
bin2decimal(val+2, &dec, precision, scale); bin2decimal(val+2, &dec, precision, scale);
decimal2string(&dec, str_buf, &str_len, 0, 0, 0); decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
str_buf[str_len]= 0; str_buf[str_len]= 0;
fprintf(file, ":=%s;\n",str_buf); my_b_printf(&cache, ":=%s;\n",str_buf);
break; break;
} }
case STRING_RESULT: case STRING_RESULT:
...@@ -3800,9 +3945,9 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -3800,9 +3945,9 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
Generate an unusable command (=> syntax error) is probably the best Generate an unusable command (=> syntax error) is probably the best
thing we can do here. thing we can do here.
*/ */
fprintf(file, ":=???;\n"); my_b_printf(&cache, ":=???;\n");
else else
fprintf(file, ":=_%s %s COLLATE `%s`;\n", cs->csname, hex_str, cs->name); my_b_printf(&cache, ":=_%s %s COLLATE `%s`;\n", cs->csname, hex_str, cs->name);
my_afree(hex_str); my_afree(hex_str);
} }
break; break;
...@@ -3812,7 +3957,6 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) ...@@ -3812,7 +3957,6 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
return; return;
} }
} }
fflush(file);
} }
#endif #endif
...@@ -3896,13 +4040,14 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) ...@@ -3896,13 +4040,14 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Unknown_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
if (print_event_info->short_form) if (print_event_info->short_form)
return; return;
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fputc('\n', file); my_b_printf(&cache, "\n# %s", "Unknown event\n");
fprintf(file, "# %s", "Unknown event\n");
} }
#endif #endif
...@@ -3969,12 +4114,13 @@ Slave_log_event::~Slave_log_event() ...@@ -3969,12 +4114,13 @@ Slave_log_event::~Slave_log_event()
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Slave_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Slave_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file);
char llbuff[22]; char llbuff[22];
if (print_event_info->short_form) if (print_event_info->short_form)
return; return;
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fputc('\n', file); my_b_printf(&cache, "\n\
fprintf(file, "\
Slave: master_host: '%s' master_port: %d master_log: '%s' master_pos: %s\n", Slave: master_host: '%s' master_port: %d master_log: '%s' master_pos: %s\n",
master_host, master_port, master_log, llstr(master_pos, llbuff)); master_host, master_port, master_log, llstr(master_pos, llbuff));
} }
...@@ -4054,12 +4200,14 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli) ...@@ -4054,12 +4200,14 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli)
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
if (print_event_info->short_form) if (print_event_info->short_form)
return; return;
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fprintf(file, "\tStop\n"); my_b_printf(&cache, "\tStop\n");
fflush(file);
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -4234,6 +4382,8 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len, ...@@ -4234,6 +4382,8 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info, void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info,
bool enable_local) bool enable_local)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file);
if (print_event_info->short_form) if (print_event_info->short_form)
{ {
if (enable_local && check_fname_outside_temp_buf()) if (enable_local && check_fname_outside_temp_buf())
...@@ -4249,10 +4399,10 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info ...@@ -4249,10 +4399,10 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't. SHOW BINLOG EVENTS we don't.
*/ */
fprintf(file, "#"); my_b_printf(&cache, "#");
} }
fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len);
} }
...@@ -4422,12 +4572,13 @@ bool Append_block_log_event::write(IO_CACHE* file) ...@@ -4422,12 +4572,13 @@ bool Append_block_log_event::write(IO_CACHE* file)
void Append_block_log_event::print(FILE* file, void Append_block_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info) PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file);
if (print_event_info->short_form) if (print_event_info->short_form)
return; return;
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fputc('\n', file); my_b_printf(&cache, "\n#%s: file_id: %d block_len: %d\n",
fprintf(file, "#%s: file_id: %d block_len: %d\n", get_type_str(), file_id, block_len);
get_type_str(), file_id, block_len);
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -4565,11 +4716,12 @@ bool Delete_file_log_event::write(IO_CACHE* file) ...@@ -4565,11 +4716,12 @@ bool Delete_file_log_event::write(IO_CACHE* file)
void Delete_file_log_event::print(FILE* file, void Delete_file_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info) PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file);
if (print_event_info->short_form) if (print_event_info->short_form)
return; return;
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fputc('\n', file); my_b_printf(&cache, "\n#Delete_file: file_id=%u\n", file_id);
fprintf(file, "#Delete_file: file_id=%u\n", file_id);
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
...@@ -4660,12 +4812,13 @@ bool Execute_load_log_event::write(IO_CACHE* file) ...@@ -4660,12 +4812,13 @@ bool Execute_load_log_event::write(IO_CACHE* file)
void Execute_load_log_event::print(FILE* file, void Execute_load_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info) PRINT_EVENT_INFO* print_event_info)
{ {
Write_on_release_cache cache(&print_event_info->head_cache, file);
if (print_event_info->short_form) if (print_event_info->short_form)
return; return;
print_header(file, print_event_info); print_header(&cache, print_event_info, FALSE);
fputc('\n', file); my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
fprintf(file, "#Exec_load: file_id=%d\n", file_id);
file_id);
} }
#endif #endif
...@@ -4882,29 +5035,30 @@ void Execute_load_query_log_event::print(FILE* file, ...@@ -4882,29 +5035,30 @@ void Execute_load_query_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info, PRINT_EVENT_INFO* print_event_info,
const char *local_fname) const char *local_fname)
{ {
print_query_header(file, print_event_info); Write_on_release_cache cache(&print_event_info->head_cache, file);
print_query_header(&cache, print_event_info);
if (local_fname) if (local_fname)
{ {
my_fwrite(file, (byte*) query, fn_pos_start, MYF(MY_NABP | MY_WME)); my_b_write(&cache, (byte*) query, fn_pos_start);
fprintf(file, " LOCAL INFILE \'"); my_b_printf(&cache, " LOCAL INFILE \'");
fprintf(file, local_fname); my_b_printf(&cache, local_fname);
fprintf(file, "\'"); my_b_printf(&cache, "\'");
if (dup_handling == LOAD_DUP_REPLACE) if (dup_handling == LOAD_DUP_REPLACE)
fprintf(file, " REPLACE"); my_b_printf(&cache, " REPLACE");
fprintf(file, " INTO"); my_b_printf(&cache, " INTO");
my_fwrite(file, (byte*) query + fn_pos_end, q_len-fn_pos_end, my_b_write(&cache, (byte*) query + fn_pos_end, q_len-fn_pos_end);
MYF(MY_NABP | MY_WME)); my_b_printf(&cache, ";\n");
fprintf(file, ";\n");
} }
else else
{ {
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); my_b_write(&cache, (byte*) query, q_len);
fprintf(file, ";\n"); my_b_printf(&cache, ";\n");
} }
if (!print_event_info->short_form) if (!print_event_info->short_form)
fprintf(file, "# file_id: %d \n", file_id); my_b_printf(&cache, "# file_id: %d \n", file_id);
} }
#endif #endif
...@@ -5639,6 +5793,31 @@ void Rows_log_event::pack_info(Protocol *protocol) ...@@ -5639,6 +5793,31 @@ void Rows_log_event::pack_info(Protocol *protocol)
} }
#endif #endif
#ifdef MYSQL_CLIENT
void Rows_log_event::print_helper(FILE *file,
PRINT_EVENT_INFO *print_event_info,
char const *const name)
{
IO_CACHE *const head= &print_event_info->head_cache;
IO_CACHE *const body= &print_event_info->body_cache;
if (!print_event_info->short_form)
{
bool const last_stmt_event= get_flags(STMT_END_F);
print_header(head, print_event_info, !last_stmt_event);
my_b_printf(head, "\t%s: table id %lu", name, m_table_id);
print_base64(body, print_event_info, !last_stmt_event);
}
if (get_flags(STMT_END_F))
{
my_b_copy_to_file(head, file);
my_b_copy_to_file(body, file);
reinit_io_cache(head, WRITE_CACHE, 0, FALSE, TRUE);
reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE);
}
}
#endif
/************************************************************************** /**************************************************************************
Table_map_log_event member functions Table_map_log_event member functions
**************************************************************************/ **************************************************************************/
...@@ -6049,10 +6228,11 @@ void Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info) ...@@ -6049,10 +6228,11 @@ void Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
{ {
if (!print_event_info->short_form) if (!print_event_info->short_form)
{ {
print_header(file, print_event_info); print_header(&print_event_info->head_cache, print_event_info, TRUE);
fprintf(file, "\tTable_map: `%s`.`%s` mapped to number %lu\n", my_b_printf(&print_event_info->head_cache,
m_dbnam, m_tblnam, m_table_id); "\tTable_map: `%s`.`%s` mapped to number %lu\n",
print_base64(file, print_event_info); m_dbnam, m_tblnam, m_table_id);
print_base64(&print_event_info->body_cache, print_event_info, TRUE);
} }
} }
#endif #endif
...@@ -6315,12 +6495,7 @@ int Write_rows_log_event::do_exec_row(TABLE *table) ...@@ -6315,12 +6495,7 @@ int Write_rows_log_event::do_exec_row(TABLE *table)
#ifdef MYSQL_CLIENT #ifdef MYSQL_CLIENT
void Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info) void Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
{ {
if (!print_event_info->short_form) Rows_log_event::print_helper(file, print_event_info, "Write_rows");
{
print_header(file, print_event_info);
fprintf(file, "\tWrite_rows: table id %lu", m_table_id);
print_base64(file, print_event_info);
}
} }
#endif #endif
...@@ -6644,12 +6819,7 @@ int Delete_rows_log_event::do_exec_row(TABLE *table) ...@@ -6644,12 +6819,7 @@ int Delete_rows_log_event::do_exec_row(TABLE *table)
void Delete_rows_log_event::print(FILE *file, void Delete_rows_log_event::print(FILE *file,
PRINT_EVENT_INFO* print_event_info) PRINT_EVENT_INFO* print_event_info)
{ {
if (!print_event_info->short_form) Rows_log_event::print_helper(file, print_event_info, "Delete_rows");
{
print_header(file, print_event_info);
fprintf(file, "\tDelete_rows: table id %lu", m_table_id);
print_base64(file, print_event_info);
}
} }
#endif #endif
...@@ -6800,12 +6970,7 @@ int Update_rows_log_event::do_exec_row(TABLE *table) ...@@ -6800,12 +6970,7 @@ int Update_rows_log_event::do_exec_row(TABLE *table)
void Update_rows_log_event::print(FILE *file, void Update_rows_log_event::print(FILE *file,
PRINT_EVENT_INFO* print_event_info) PRINT_EVENT_INFO* print_event_info)
{ {
if (!print_event_info->short_form) Rows_log_event::print_helper(file, print_event_info, "Update_rows");
{
print_header(file, print_event_info);
fprintf(file, "\tUpdate_rows: table id %lu", m_table_id);
print_base64(file, print_event_info);
}
} }
#endif #endif
......
...@@ -519,14 +519,30 @@ typedef struct st_print_event_info ...@@ -519,14 +519,30 @@ typedef struct st_print_event_info
bzero(db, sizeof(db)); bzero(db, sizeof(db));
bzero(charset, sizeof(charset)); bzero(charset, sizeof(charset));
bzero(time_zone_str, sizeof(time_zone_str)); bzero(time_zone_str, sizeof(time_zone_str));
uint const flags = MYF(MY_WME | MY_NABP);
init_io_cache(&head_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
init_io_cache(&body_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
} }
~st_print_event_info() {
end_io_cache(&head_cache);
end_io_cache(&body_cache);
}
/* Settings on how to print the events */ /* Settings on how to print the events */
bool short_form; bool short_form;
bool base64_output; bool base64_output;
my_off_t hexdump_from; my_off_t hexdump_from;
uint8 common_header_len; uint8 common_header_len;
/*
These two caches are used by the row-based replication events to
collect the header information and the main body of the events
making up a statement.
*/
IO_CACHE head_cache;
IO_CACHE body_cache;
} PRINT_EVENT_INFO; } PRINT_EVENT_INFO;
#endif #endif
...@@ -637,9 +653,11 @@ public: ...@@ -637,9 +653,11 @@ public:
const Format_description_log_event *description_event); const Format_description_log_event *description_event);
/* print*() functions are used by mysqlbinlog */ /* print*() functions are used by mysqlbinlog */
virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0; virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
void print_timestamp(FILE* file, time_t *ts = 0); void print_timestamp(IO_CACHE* file, time_t *ts = 0);
void print_header(FILE* file, PRINT_EVENT_INFO* print_event_info); void print_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
void print_base64(FILE* file, PRINT_EVENT_INFO* print_event_info); bool is_more);
void print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
bool is_more);
#endif #endif
static void *operator new(size_t size) static void *operator new(size_t size)
...@@ -804,7 +822,7 @@ public: ...@@ -804,7 +822,7 @@ public:
uint32 q_len_arg); uint32 q_len_arg);
#endif /* HAVE_REPLICATION */ #endif /* HAVE_REPLICATION */
#else #else
void print_query_header(FILE* file, PRINT_EVENT_INFO* print_event_info); void print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info);
void print(FILE* file, PRINT_EVENT_INFO* print_event_info); void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif #endif
...@@ -1843,6 +1861,10 @@ protected: ...@@ -1843,6 +1861,10 @@ protected:
Log_event_type event_type, Log_event_type event_type,
const Format_description_log_event *description_event); const Format_description_log_event *description_event);
#ifdef MYSQL_CLIENT
void print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
#endif
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
virtual int do_add_row_data(byte *data, my_size_t length); virtual int do_add_row_data(byte *data, my_size_t length);
#endif #endif
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
void mysql_client_binlog_statement(THD* thd) void mysql_client_binlog_statement(THD* thd)
{ {
DBUG_ENTER("mysql_client_binlog_statement");
DBUG_PRINT("info",("binlog base64: '%*s'", DBUG_PRINT("info",("binlog base64: '%*s'",
(thd->lex->comment.length < 2048 ? (thd->lex->comment.length < 2048 ?
thd->lex->comment.length : 2048), thd->lex->comment.length : 2048),
...@@ -43,8 +44,8 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -43,8 +44,8 @@ void mysql_client_binlog_statement(THD* thd)
my_bool nsok= thd->net.no_send_ok; my_bool nsok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE; thd->net.no_send_ok= TRUE;
const my_size_t coded_len= thd->lex->comment.length + 1; my_size_t coded_len= thd->lex->comment.length + 1;
const my_size_t event_len= base64_needed_decoded_length(coded_len); my_size_t decoded_len= base64_needed_decoded_length(coded_len);
DBUG_ASSERT(coded_len > 0); DBUG_ASSERT(coded_len > 0);
/* /*
...@@ -57,9 +58,8 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -57,9 +58,8 @@ void mysql_client_binlog_statement(THD* thd)
new Format_description_log_event(4); new Format_description_log_event(4);
const char *error= 0; const char *error= 0;
char *buf= (char *) my_malloc(event_len, MYF(MY_WME)); char *buf= (char *) my_malloc(decoded_len, MYF(MY_WME));
Log_event *ev = 0; Log_event *ev = 0;
int res;
/* /*
Out of memory check Out of memory check
...@@ -73,43 +73,97 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -73,43 +73,97 @@ void mysql_client_binlog_statement(THD* thd)
thd->rli_fake->sql_thd= thd; thd->rli_fake->sql_thd= thd;
thd->rli_fake->no_storage= TRUE; thd->rli_fake->no_storage= TRUE;
res= base64_decode(thd->lex->comment.str, coded_len, buf); for (char const *strptr= thd->lex->comment.str ;
strptr < thd->lex->comment.str + thd->lex->comment.length ; )
DBUG_PRINT("info",("binlog base64 decoded_len=%d, event_len=%d\n",
res, uint4korr(buf + EVENT_LEN_OFFSET)));
/*
Note that 'res' is the correct event length, 'event_len' was
calculated based on the base64-string that possibly contained
extra spaces, so it can be longer than the real event.
*/
if (res < EVENT_LEN_OFFSET
|| (uint) res != uint4korr(buf+EVENT_LEN_OFFSET))
{ {
my_error(ER_SYNTAX_ERROR, MYF(0)); char const *endptr= 0;
goto end; int bytes_decoded= base64_decode(strptr, coded_len, buf, &endptr);
}
DBUG_PRINT("info",
ev= Log_event::read_log_event(buf, res, &error, desc); ("bytes_decoded=%d; strptr=0x%lu; endptr=0x%lu ('%c':%d)",
bytes_decoded, strptr, endptr, *endptr, *endptr));
if (bytes_decoded < 0)
{
my_error(ER_BASE64_DECODE_ERROR, MYF(0));
goto end;
}
else if (bytes_decoded == 0)
break; // If no bytes where read, the string contained only whitespace
DBUG_ASSERT(bytes_decoded > 0);
DBUG_ASSERT(endptr > strptr);
coded_len-= endptr - strptr;
strptr= endptr;
DBUG_PRINT("info",("binlog base64 err=%s", error));
if (!ev)
{
/* /*
This could actually be an out-of-memory, but it is more Now we have one or more events stored in the buffer. The size of
likely causes by a bad statement the buffer is computed based on how much base64-encoded data
there were, so there should be ample space for the data (maybe
even too much, since a statement can consist of a considerable
number of events).
TODO: Switch to use a stream-based base64 encoder/decoder in
order to be able to read exactly what is necessary.
*/ */
my_error(ER_SYNTAX_ERROR, MYF(0));
goto end;
}
DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code())); DBUG_PRINT("info",("binlog base64 decoded_len=%d, bytes_decoded=%d",
DBUG_PRINT("info",("buf+EVENT_TYPE_OFFSET=%d", buf+EVENT_TYPE_OFFSET)); decoded_len, bytes_decoded));
ev->thd= thd; /*
if (ev->exec_event(thd->rli_fake)) Now we start to read events of the buffer, until there are no
{ more.
my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); */
goto end; for (char *bufptr= buf ; bytes_decoded > 0 ; )
{
/*
Checking that the first event in the buffer is not truncated.
*/
ulong event_len= uint4korr(bufptr + EVENT_LEN_OFFSET);
DBUG_PRINT("info", ("event_len=%lu, bytes_decoded=%d",
event_len, bytes_decoded));
if (bytes_decoded < EVENT_LEN_OFFSET || (uint) bytes_decoded < event_len)
{
my_error(ER_SYNTAX_ERROR, MYF(0));
goto end;
}
ev= Log_event::read_log_event(bufptr, event_len, &error, desc);
DBUG_PRINT("info",("binlog base64 err=%s", error));
if (!ev)
{
/*
This could actually be an out-of-memory, but it is more likely
causes by a bad statement
*/
my_error(ER_SYNTAX_ERROR, MYF(0));
goto end;
}
bytes_decoded -= event_len;
bufptr += event_len;
DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code()));
DBUG_PRINT("info",("bufptr+EVENT_TYPE_OFFSET=0x%lx",
bufptr+EVENT_TYPE_OFFSET));
DBUG_PRINT("info", ("bytes_decoded=%d; bufptr=0x%lx; buf[EVENT_LEN_OFFSET]=%u",
bytes_decoded, bufptr, uint4korr(bufptr+EVENT_LEN_OFFSET)));
ev->thd= thd;
if (int err= ev->exec_event(thd->rli_fake))
{
DBUG_PRINT("info", ("exec_event() - error=%d", error));
/*
TODO: Maybe a better error message since the BINLOG statement
now contains several events.
*/
my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement");
goto end;
}
delete ev;
ev= 0;
}
} }
/* /*
...@@ -126,10 +180,7 @@ end: ...@@ -126,10 +180,7 @@ end:
*/ */
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
if (ev) delete desc;
delete ev; my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
if (desc) DBUG_VOID_RETURN;
delete desc;
if (buf)
my_free(buf, MYF(0));
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment