diff options
author | unknown <mats@romeo.(none)> | 2007-02-21 13:52:42 +0100 |
---|---|---|
committer | unknown <mats@romeo.(none)> | 2007-02-21 13:52:42 +0100 |
commit | e1a360ad62b1800b6adc4b97c2604b59eea881d2 (patch) | |
tree | 66f14587ebe96d0c8c501fb84d0831e9f4165fd0 /sql/sql_class.cc | |
parent | af71cac0e44da5e1671c9f8fca2cd4b99f9eb02e (diff) | |
parent | e4146a9f7a9945ea8c5654fa9aba8ccdd05c6c4a (diff) | |
download | mariadb-git-e1a360ad62b1800b6adc4b97c2604b59eea881d2.tar.gz |
Merging with mysql-5.1-new-rpl
mysql-test/r/rpl_row_delayed_ins.result:
Manual merge.
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r-- | sql/sql_class.cc | 113 |
1 files changed, 98 insertions, 15 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7309e79a666..9025adb322d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2493,30 +2493,113 @@ my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const } -my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data, - const byte *record) const +/* + Pack a record of data for a table into a format suitable for + transfer via the binary log. + + SYNOPSIS + THD::pack_row() + table Table describing the format of the record + cols Bitmap with a set bit for each column that should be + stored in the row + row_data Pointer to memory where row will be written + record Pointer to record that should be packed. It is assumed + that the pointer refers to either record[0] or + record[1], but no such check is made since the code does + not rely on that. + + DESCRIPTION + + The format for a row in transfer with N fields is the following: + + ceil(N/8) null bytes: + One null bit for every column *regardless of whether it can be + null or not*. This simplifies the decoding. Observe that the + number of null bits is equal to the number of set bits in the + 'cols' bitmap. The number of null bytes is the smallest number + of bytes necessary to store the null bits. + + Padding bits are 1. + + N packets: + Each field is stored in packed format. + + + RETURN VALUE + + The number of bytes written at 'row_data'. + */ +my_size_t +THD::pack_row(TABLE *table, MY_BITMAP const* cols, + byte *const row_data, const byte *record) const { Field **p_field= table->field, *field; - int n_null_bytes= table->s->null_bytes; - byte *ptr; - uint i; + int const null_byte_count= (bitmap_bits_set(cols) + 7) / 8; + byte *pack_ptr = row_data + null_byte_count; + byte *null_ptr = row_data; my_ptrdiff_t const rec_offset= record - table->record[0]; my_ptrdiff_t const def_offset= table->s->default_values - table->record[0]; - memcpy(row_data, record, n_null_bytes); - ptr= row_data+n_null_bytes; - for (i= 0 ; (field= *p_field) ; i++, p_field++) + /* + We write the null bits and the packed records using one pass + through all the fields. The null bytes are written little-endian, + i.e., the first fields are in the first byte. + */ + unsigned int null_bits= (1U << 8) - 1; + // Mask to mask out the correct but among the null bits + unsigned int null_mask= 1U; + for ( ; (field= *p_field) ; p_field++) { - if (bitmap_is_set(cols,i)) + DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d", + null_mask, null_ptr, row_data, null_byte_count)); + if (bitmap_is_set(cols, p_field - table->field)) { - my_ptrdiff_t const offset= - field->is_null(rec_offset) ? def_offset : rec_offset; - field->move_field_offset(offset); - ptr= (byte*)field->pack((char *) ptr, field->ptr); - field->move_field_offset(-offset); + my_ptrdiff_t offset; + if (field->is_null(rec_offset)) + { + offset= def_offset; + null_bits |= null_mask; + } + else + { + offset= rec_offset; + null_bits &= ~null_mask; + + /* + We only store the data of the field if it is non-null + */ + field->move_field_offset(offset); + pack_ptr= (byte*)field->pack((char *) pack_ptr, field->ptr); + field->move_field_offset(-offset); + } + + null_mask <<= 1; + if ((null_mask & 0xFF) == 0) + { + DBUG_ASSERT(null_ptr < row_data + null_byte_count); + null_mask = 1U; + *null_ptr++ = null_bits; + null_bits= (1U << 8) - 1; + } } } - return (static_cast<my_size_t>(ptr - row_data)); + + /* + Write the last (partial) byte, if there is one + */ + if ((null_mask & 0xFF) > 1) + { + DBUG_ASSERT(null_ptr < row_data + null_byte_count); + *null_ptr++ = null_bits; + } + + /* + The null pointer should now point to the first byte of the + packed data. If it doesn't, something is very wrong. + */ + DBUG_ASSERT(null_ptr == row_data + null_byte_count); + + return static_cast<my_size_t>(pack_ptr - row_data); } |