summaryrefslogtreecommitdiff
path: root/sql/log_event.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/log_event.cc')
-rw-r--r--sql/log_event.cc101
1 files changed, 85 insertions, 16 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc
index b8d80883451..3b69e1c3176 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -203,6 +203,29 @@ static inline int read_str(char * &buf, char *buf_end, char * &str,
}
/*
+ Transforms a string into "" or its expression in 0x... form.
+*/
+static char *str_to_hex(char *to, char *from, uint len)
+{
+ char *p= to;
+ if (len)
+ {
+ p= strmov(p, "0x");
+ for (uint i= 0; i < len; i++, p+= 2)
+ {
+ /* val[i] is char. Casting to uchar helps greatly if val[i] < 0 */
+ uint tmp= (uint) (uchar) from[i];
+ p[0]= _dig_vec_upper[tmp >> 4];
+ p[1]= _dig_vec_upper[tmp & 15];
+ }
+ *p= 0;
+ }
+ else
+ p= strmov(p, "\"\"");
+ return p; // pointer to end 0 of 'to'
+}
+
+/*
Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
commands just before it prints a query.
*/
@@ -607,6 +630,7 @@ end:
#else
#define UNLOCK_MUTEX
#define LOCK_MUTEX
+#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet)
#endif
/*
@@ -2910,7 +2934,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
void User_var_log_event::pack_info(Protocol* protocol)
{
char *buf= 0;
- uint val_offset= 2 + name_len;
+ uint val_offset= 4 + name_len;
uint event_len= val_offset;
if (is_null)
@@ -2934,16 +2958,21 @@ void User_var_log_event::pack_info(Protocol* protocol)
event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
break;
case STRING_RESULT:
- /*
- This is correct as pack_info is used for SHOW BINLOG command
- only. But be carefull this is may be incorrect in other cases as
- string may contain \ and '.
- */
- event_len= val_offset + 2 + val_len;
- buf= my_malloc(event_len, MYF(MY_WME));
- buf[val_offset]= '\'';
- memcpy(buf + val_offset + 1, val, val_len);
- buf[val_offset + val_len + 1]= '\'';
+ /* 15 is for 'COLLATE' and other chars */
+ buf= my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, MYF(MY_WME));
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ {
+ strmov(buf+val_offset, "???");
+ event_len+= 3;
+ }
+ else
+ {
+ char *p= strxmov(buf + val_offset, "_", cs->csname, " ", NullS);
+ p= str_to_hex(p, val, val_len);
+ p= strxmov(p, " COLLATE ", cs->name, NullS);
+ event_len= p-buf;
+ }
break;
case ROW_RESULT:
default:
@@ -2952,8 +2981,10 @@ void User_var_log_event::pack_info(Protocol* protocol)
}
}
buf[0]= '@';
- buf[1+name_len]= '=';
- memcpy(buf+1, name, name_len);
+ buf[1]= '`';
+ buf[2+name_len]= '`';
+ buf[3+name_len]= '=';
+ memcpy(buf+2, name, name_len);
protocol->store(buf, event_len, &my_charset_bin);
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
@@ -3046,8 +3077,9 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las
fprintf(file, "\tUser_var\n");
}
- fprintf(file, "SET @");
+ fprintf(file, "SET @`");
my_fwrite(file, (byte*) name, (uint) (name_len), MYF(MY_NABP | MY_WME));
+ fprintf(file, "`");
if (is_null)
{
@@ -3067,7 +3099,42 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las
fprintf(file, ":=%s;\n", int_buf);
break;
case STRING_RESULT:
- fprintf(file, ":='%s';\n", val);
+ {
+ /*
+ Let's express the string in hex. That's the most robust way. If we
+ print it in character form instead, we need to escape it with
+ character_set_client which we don't know (we will know it in 5.0, but
+ in 4.1 we don't know it easily when we are printing
+ User_var_log_event). Explanation why we would need to bother with
+ character_set_client (quoting Bar):
+ > Note, the parser doesn't switch to another unescaping mode after
+ > it has met a character set introducer.
+ > For example, if an SJIS client says something like:
+ > SET @a= _ucs2 \0a\0b'
+ > the string constant is still unescaped according to SJIS, not
+ > according to UCS2.
+ */
+ char *p, *q;
+ if (!(p= (char *)my_alloca(2*val_len+1+2))) // 2 hex digits per byte
+ break; // no error, as we are 'void'
+ str_to_hex(p, val, val_len);
+ /*
+ For proper behaviour when mysqlbinlog|mysql, we need to explicitely
+ specify the variable's collation. It will however cause problems when
+ people want to mysqlbinlog|mysql into another server not supporting the
+ character set. But there's not much to do about this and it's unlikely.
+ */
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ /*
+ Generate an unusable command (=> syntax error) is probably the best
+ thing we can do here.
+ */
+ fprintf(file, ":=???;\n");
+ else
+ fprintf(file, ":=_%s %s COLLATE %s;\n", cs->csname, p, cs->name);
+ my_afree(p);
+ }
break;
case ROW_RESULT:
default:
@@ -3088,7 +3155,9 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las
int User_var_log_event::exec_event(struct st_relay_log_info* rli)
{
Item *it= 0;
- CHARSET_INFO *charset= get_charset(charset_number, MYF(0));
+ CHARSET_INFO *charset;
+ if (!(charset= get_charset(charset_number, MYF(MY_WME))))
+ return 1;
LEX_STRING user_var_name;
user_var_name.str= name;
user_var_name.length= name_len;