Skip to content

Commit 00e65b5

Browse files
author
Mats Kindahl
committed
Bug #52131: SET and ENUM stored endian-dependent in binary log
Replication SET and ENUM fields from a big-endian to a little- endian machine (or the opposite) that are represented using more than 1 byte (SET fields with more than 8 members or ENUM fields with more than 256 constants) will fail to replicate correctly when using row-based replication. The reason is that there are no pack() or unpack() functions for Field_set or Field_enum, which make them rely on Field::pack and Field::unpack. These functions pack data as strings, but since Field_set and Field_enum use integral types for representation, the fields are stored incorrectly on big-endian machines. This patch adds Field_enum::pack and Field_enum::unpack functions that store the integral value correctly in the binary log even on big-endian machines. Since Field_set inherits from Field_enum, it will use the same functions for packing and unpacking the field. --BZR-- revision-id: [email protected] property-branch-nick: b52131-5.5 property-file-info: ld7:file_id61:sp1f-field.cc-19700101030959-f4imaofclsea3n4fj4ow5m7havmyxa2r7:message100:Removing some obsolete debug printouts and adding Field_enum::pack property-file-info: and Field_enum::unpack functions.4:path12:sql/field.cced7:file_id60:sp1f-field.h-19700101030959-3n6smzxcwkjl7bikm3wg4hfkjn66uvvp7:message149:Adding helper functions for packing and unpacking 16- and property-file-info: 24-bit integral types. property-file-info: property-file-info: Field_short::pack and Field_short::unpack now use these functions. property-file-info: 4:path11:sql/field.hed7:file_id66:sp1f-rpl_record.cc-20070413125523-wuthuk5jk7uxikuioz6esll6xakdngs47:message72:Removing some obsolete debug printouts and adding some property-file-info: more useful ones.4:path17:sql/rpl_record.ccee testament3-sha1: 10ef1f6aef027a8b18b90e24379a3c0d4e97540a
1 parent 241a67e commit 00e65b5

3 files changed

Lines changed: 127 additions & 42 deletions

File tree

sql/field.cc

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7725,12 +7725,6 @@ void Field_blob::sql_type(String &res) const
77257725
uchar *Field_blob::pack(uchar *to, const uchar *from,
77267726
uint max_length, bool low_byte_first)
77277727
{
7728-
DBUG_ENTER("Field_blob::pack");
7729-
DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;"
7730-
" max_length: %u; low_byte_first: %d",
7731-
(ulong) to, (ulong) from,
7732-
max_length, low_byte_first));
7733-
DBUG_DUMP("record", from, table->s->reclength);
77347728
uchar *save= ptr;
77357729
ptr= (uchar*) from;
77367730
uint32 length=get_length(); // Length of from string
@@ -7751,8 +7745,7 @@ uchar *Field_blob::pack(uchar *to, const uchar *from,
77517745
memcpy(to+packlength, from,length);
77527746
}
77537747
ptr=save; // Restore org row pointer
7754-
DBUG_DUMP("packed", to, packlength + length);
7755-
DBUG_RETURN(to+packlength+length);
7748+
return to+packlength+length;
77567749
}
77577750

77587751

@@ -8396,6 +8389,50 @@ uint Field_enum::is_equal(Create_field *new_field)
83968389
}
83978390

83988391

8392+
uchar *Field_enum::pack(uchar *to, const uchar *from,
8393+
uint max_length, bool low_byte_first)
8394+
{
8395+
DBUG_ENTER("Field_enum::pack");
8396+
DBUG_PRINT("debug", ("packlength: %d", packlength));
8397+
DBUG_DUMP("from", from, packlength);
8398+
8399+
switch (packlength)
8400+
{
8401+
case 1:
8402+
*to = *from;
8403+
DBUG_RETURN(to + 1);
8404+
case 2: DBUG_RETURN(pack_int16(to, from, low_byte_first));
8405+
case 3: DBUG_RETURN(pack_int24(to, from, low_byte_first));
8406+
case 4: DBUG_RETURN(pack_int32(to, from, low_byte_first));
8407+
case 8: DBUG_RETURN(pack_int64(to, from, low_byte_first));
8408+
default:
8409+
DBUG_ASSERT(0);
8410+
}
8411+
}
8412+
8413+
const uchar *Field_enum::unpack(uchar *to, const uchar *from,
8414+
uint param_data, bool low_byte_first)
8415+
{
8416+
DBUG_ENTER("Field_enum::unpack");
8417+
DBUG_PRINT("debug", ("packlength: %d", packlength));
8418+
DBUG_DUMP("from", from, packlength);
8419+
8420+
switch (packlength)
8421+
{
8422+
case 1:
8423+
*to = *from;
8424+
DBUG_RETURN(from + 1);
8425+
8426+
case 2: DBUG_RETURN(unpack_int16(to, from, low_byte_first));
8427+
case 3: DBUG_RETURN(unpack_int24(to, from, low_byte_first));
8428+
case 4: DBUG_RETURN(unpack_int32(to, from, low_byte_first));
8429+
case 8: DBUG_RETURN(unpack_int64(to, from, low_byte_first));
8430+
default:
8431+
DBUG_ASSERT(0);
8432+
}
8433+
}
8434+
8435+
83998436
/**
84008437
@return
84018438
returns 1 if the fields are equally defined

sql/field.h

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,48 @@ class Field
554554
{ return 0; }
555555

556556
protected:
557+
static void handle_int16(uchar *to, const uchar *from,
558+
bool low_byte_first_from, bool low_byte_first_to)
559+
{
560+
int16 val;
561+
#ifdef WORDS_BIGENDIAN
562+
if (low_byte_first_from)
563+
val = sint2korr(from);
564+
else
565+
#endif
566+
shortget(val, from);
567+
568+
#ifdef WORDS_BIGENDIAN
569+
if (low_byte_first_to)
570+
int2store(to, val);
571+
else
572+
#endif
573+
shortstore(to, val);
574+
}
575+
576+
static void handle_int24(uchar *to, const uchar *from,
577+
bool low_byte_first_from, bool low_byte_first_to)
578+
{
579+
int32 val;
580+
#ifdef WORDS_BIGENDIAN
581+
if (low_byte_first_from)
582+
val = sint3korr(from);
583+
else
584+
#endif
585+
val= (from[0] << 16) + (from[1] << 8) + from[2];
586+
587+
#ifdef WORDS_BIGENDIAN
588+
if (low_byte_first_to)
589+
int2store(to, val);
590+
else
591+
#endif
592+
{
593+
to[0]= 0xFF & (val >> 16);
594+
to[1]= 0xFF & (val >> 8);
595+
to[2]= 0xFF & val;
596+
}
597+
}
598+
557599
/*
558600
Helper function to pack()/unpack() int32 values
559601
*/
@@ -598,6 +640,32 @@ class Field
598640
longlongstore(to, val);
599641
}
600642

643+
uchar *pack_int16(uchar *to, const uchar *from, bool low_byte_first_to)
644+
{
645+
handle_int16(to, from, table->s->db_low_byte_first, low_byte_first_to);
646+
return to + sizeof(int16);
647+
}
648+
649+
const uchar *unpack_int16(uchar* to, const uchar *from,
650+
bool low_byte_first_from)
651+
{
652+
handle_int16(to, from, low_byte_first_from, table->s->db_low_byte_first);
653+
return from + sizeof(int16);
654+
}
655+
656+
uchar *pack_int24(uchar *to, const uchar *from, bool low_byte_first_to)
657+
{
658+
handle_int24(to, from, table->s->db_low_byte_first, low_byte_first_to);
659+
return to + 3;
660+
}
661+
662+
const uchar *unpack_int24(uchar* to, const uchar *from,
663+
bool low_byte_first_from)
664+
{
665+
handle_int24(to, from, low_byte_first_from, table->s->db_low_byte_first);
666+
return from + 3;
667+
}
668+
601669
uchar *pack_int32(uchar *to, const uchar *from, bool low_byte_first_to)
602670
{
603671
handle_int32(to, from, table->s->db_low_byte_first, low_byte_first_to);
@@ -918,41 +986,13 @@ class Field_short :public Field_num {
918986
virtual uchar *pack(uchar* to, const uchar *from,
919987
uint max_length, bool low_byte_first)
920988
{
921-
int16 val;
922-
#ifdef WORDS_BIGENDIAN
923-
if (table->s->db_low_byte_first)
924-
val = sint2korr(from);
925-
else
926-
#endif
927-
shortget(val, from);
928-
929-
#ifdef WORDS_BIGENDIAN
930-
if (low_byte_first)
931-
int2store(to, val);
932-
else
933-
#endif
934-
shortstore(to, val);
935-
return to + sizeof(val);
989+
return pack_int16(to, from, low_byte_first);
936990
}
937991

938992
virtual const uchar *unpack(uchar* to, const uchar *from,
939993
uint param_data, bool low_byte_first)
940994
{
941-
int16 val;
942-
#ifdef WORDS_BIGENDIAN
943-
if (low_byte_first)
944-
val = sint2korr(from);
945-
else
946-
#endif
947-
shortget(val, from);
948-
949-
#ifdef WORDS_BIGENDIAN
950-
if (table->s->db_low_byte_first)
951-
int2store(to, val);
952-
else
953-
#endif
954-
shortstore(to, val);
955-
return from + sizeof(val);
995+
return unpack_int16(to, from, low_byte_first);
956996
}
957997
};
958998

@@ -1895,6 +1935,12 @@ class Field_enum :public Field_str {
18951935
bool has_charset(void) const { return TRUE; }
18961936
/* enum and set are sorted as integers */
18971937
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
1938+
1939+
virtual uchar *pack(uchar *to, const uchar *from,
1940+
uint max_length, bool low_byte_first);
1941+
virtual const uchar *unpack(uchar *to, const uchar *from,
1942+
uint param_data, bool low_byte_first);
1943+
18981944
private:
18991945
int do_save_field_metadata(uchar *first_byte);
19001946
uint is_equal(Create_field *new_field);

sql/rpl_record.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
7878
unsigned int null_mask= 1U;
7979
for ( ; (field= *p_field) ; p_field++)
8080
{
81-
DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
82-
null_mask, null_ptr, row_data, null_byte_count));
8381
if (bitmap_is_set(cols, p_field - table->field))
8482
{
8583
my_ptrdiff_t offset;
@@ -110,6 +108,7 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
110108
field->field_name, field->real_type(),
111109
(ulong) old_pack_ptr, (ulong) pack_ptr,
112110
(int) (pack_ptr - old_pack_ptr)));
111+
DBUG_DUMP("packed_data", old_pack_ptr, pack_ptr - old_pack_ptr);
113112
}
114113

115114
null_mask <<= 1;
@@ -380,8 +379,11 @@ unpack_row(Relay_log_info const *rli,
380379
}
381380
DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set
382381

383-
if (!((null_bits & null_mask) && tabledef->maybe_null(i)))
384-
pack_ptr+= tabledef->calc_field_size(i, (uchar *) pack_ptr);
382+
if (!((null_bits & null_mask) && tabledef->maybe_null(i))) {
383+
uint32 len= tabledef->calc_field_size(i, (uchar *) pack_ptr);
384+
DBUG_DUMP("field_data", pack_ptr, len);
385+
pack_ptr+= len;
386+
}
385387
null_mask <<= 1;
386388
}
387389
}

0 commit comments

Comments
 (0)