summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorLuis Soares <luis.soares@sun.com>2010-01-15 17:52:46 +0000
committerLuis Soares <luis.soares@sun.com>2010-01-15 17:52:46 +0000
commit2afa7085e90a257d92f97c8c064cb26c6f95cfae (patch)
tree4e680d68b35762adf3eb7e8f66e5abfc728a1d03 /sql
parent54b2371e92a723ee9d44c282b3b1c5b7baf50f89 (diff)
downloadmariadb-git-2afa7085e90a257d92f97c8c064cb26c6f95cfae.tar.gz
BUG#49562: SBR out of sync when using numeric data types + user
variable The User_var_log_event was not serializing the unsigned flag. This would cause the slave to always assume signed values. We fix this by extending the User_var_log_event to also contain information on the unsigned_flag, meaning that it gets into the binlog as well, therefore the slave will get this information as well. Events without information on unsigned flag (old events) are treated as they were before (always signed: unsigned_flag= FALSE). The information on the unsigned_flag, is shipped in an extra byte appended to the end of the User_var_log_event and added by this patch. This extra byte holds values for general purpose User_var_log_event flags which are now packed in the binlog as well. One of these flags contains information about whether the value is signed or unsigned (currently this extra byte is only used to hold data on the unsigned flag, in the future we can use it to pack extra flags if there is the need to).
Diffstat (limited to 'sql')
-rw-r--r--sql/log.cc9
-rw-r--r--sql/log_event.cc40
-rw-r--r--sql/log_event.h10
3 files changed, 51 insertions, 8 deletions
diff --git a/sql/log.cc b/sql/log.cc
index 8781fb03031..ba3aed64f21 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -4455,12 +4455,19 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
{
BINLOG_USER_VAR_EVENT *user_var_event;
get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i);
+
+ /* setting flags for user var log event */
+ uchar flags= User_var_log_event::UNDEF_F;
+ if (user_var_event->user_var_event->unsigned_flag)
+ flags|= User_var_log_event::UNSIGNED_F;
+
User_var_log_event e(thd, user_var_event->user_var_event->name.str,
user_var_event->user_var_event->name.length,
user_var_event->value,
user_var_event->length,
user_var_event->type,
- user_var_event->charset_number);
+ user_var_event->charset_number,
+ flags);
if (e.write(file))
goto err;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index ed47675d06a..e29eedb7611 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -5460,7 +5460,9 @@ void User_var_log_event::pack_info(Protocol* protocol)
case INT_RESULT:
if (!(buf= (char*) my_malloc(val_offset + 22, MYF(MY_WME))))
return;
- event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
+ event_len= longlong10_to_str(uint8korr(val), buf + val_offset,
+ ((flags & User_var_log_event::UNSIGNED_F) ?
+ 10 : -10))-buf;
break;
case DECIMAL_RESULT:
{
@@ -5518,12 +5520,14 @@ User_var_log_event(const char* buf,
:Log_event(buf, description_event)
{
/* The Post-Header is empty. The Variable Data part begins immediately. */
+ const char *start= buf;
buf+= description_event->common_header_len +
description_event->post_header_len[USER_VAR_EVENT-1];
name_len= uint4korr(buf);
name= (char *) buf + UV_NAME_LEN_SIZE;
buf+= UV_NAME_LEN_SIZE + name_len;
is_null= (bool) *buf;
+ flags= User_var_log_event::UNDEF_F; // defaults to UNDEF_F
if (is_null)
{
type= STRING_RESULT;
@@ -5539,6 +5543,27 @@ User_var_log_event(const char* buf,
UV_CHARSET_NUMBER_SIZE);
val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE);
+
+ /**
+ We need to check if this is from an old server
+ that did not pack information for flags.
+ We do this by checking if there are extra bytes
+ after the packed value. If there are we take the
+ extra byte and it's value is assumed to contain
+ the flags value.
+
+ Old events will not have this extra byte, thence,
+ we keep the flags set to UNDEF_F.
+ */
+ uint bytes_read= ((val + val_len) - start);
+ DBUG_ASSERT(bytes_read==data_written ||
+ bytes_read==(data_written-1));
+ if ((data_written - bytes_read) > 0)
+ {
+ flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE +
+ val_len);
+ }
}
}
@@ -5550,6 +5575,7 @@ bool User_var_log_event::write(IO_CACHE* file)
char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
uchar buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
+ uint unsigned_len= 0;
uint buf1_length;
ulong event_length;
@@ -5571,6 +5597,7 @@ bool User_var_log_event::write(IO_CACHE* file)
break;
case INT_RESULT:
int8store(buf2, *(longlong*) val);
+ unsigned_len= 1;
break;
case DECIMAL_RESULT:
{
@@ -5595,13 +5622,14 @@ bool User_var_log_event::write(IO_CACHE* file)
}
/* Length of the whole event */
- event_length= sizeof(buf)+ name_len + buf1_length + val_len;
+ event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len;
return (write_header(file, event_length) ||
my_b_safe_write(file, (uchar*) buf, sizeof(buf)) ||
my_b_safe_write(file, (uchar*) name, name_len) ||
my_b_safe_write(file, (uchar*) buf1, buf1_length) ||
- my_b_safe_write(file, pos, val_len));
+ my_b_safe_write(file, pos, val_len) ||
+ my_b_safe_write(file, (uchar*) &flags, unsigned_len));
}
#endif
@@ -5642,7 +5670,8 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
break;
case INT_RESULT:
char int_buf[22];
- longlong10_to_str(uint8korr(val), int_buf, -10);
+ longlong10_to_str(uint8korr(val), int_buf,
+ ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
my_b_printf(&cache, ":=%s%s\n", int_buf, print_event_info->delimiter);
break;
case DECIMAL_RESULT:
@@ -5789,7 +5818,8 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
a single record and with a single column. Thus, like
a column value, it could always have IMPLICIT derivation.
*/
- e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0);
+ e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT,
+ (flags & User_var_log_event::UNSIGNED_F));
free_root(thd->mem_root,0);
return 0;
diff --git a/sql/log_event.h b/sql/log_event.h
index cba0264f4ae..9b91d826da7 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2483,6 +2483,10 @@ private:
class User_var_log_event: public Log_event
{
public:
+ enum {
+ UNDEF_F= 0,
+ UNSIGNED_F= 1
+ };
char *name;
uint name_len;
char *val;
@@ -2490,12 +2494,14 @@ public:
Item_result type;
uint charset_number;
bool is_null;
+ uchar flags;
#ifndef MYSQL_CLIENT
User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
char *val_arg, ulong val_len_arg, Item_result type_arg,
- uint charset_number_arg)
+ uint charset_number_arg, uchar flags_arg)
:Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg),
- val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
+ val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg),
+ flags(flags_arg)
{ is_null= !val; }
void pack_info(Protocol* protocol);
#else