Databases Reference
In-Depth Information
Rows and keys
Now we discuss the row and key formats. The naive approach would be to store
rows in a MySQL format—what is passed to the
write_row()
function is written
to disk. Thus retrieval would be easy too. Unfortunately, this does not work. For
example, this format has all
CHAR
and
VARCHAR
fields space padded to their full
length. Storing them that way would waste a lot of space. But the main reason why
this simple approach is fundamentally flawed is the
BLOB
type. In memory, all
BLOB
(and
TEXT
) fields are kept outside of the row buffer; the row buffer only keeps a
pointer to the actual
BLOB
field content. This is why we use a special packed row
format, which makes our code only slightly more complex, as MySQL conveniently
provides a
Field::pack()
method that will do all of the packing job. First, we
need a buffer for a packed row. A growing
String
object (briefly discussed in the
previous chapter) would be very handy here. As we do not need more than one row
buffer per table, we can put it in the
ha_tocab
object:
bool ha_tocab::pack_row(const uchar *from)
{
uint max_length = table->s->reclength;
for (int i = 0; i < table->s->blob_fields ; i++) {
Field_blob *blob = (Field_blob*)
table->field[table->s->blob_field[i]];
max_length += blob->get_packed_size(from +
blob->offset(table->record[0]),
table->s->db_low_byte_first);
}
We start by calculating the required buffer size. The row length without
BLOB
fields.
is
table->s->reclength
, and for all
BLOB
fields we add up the sizes of their packed
values to get the buffer size that we need. MySQL has a
blob_field[]
array in
TABLE_SHARE
, it is an array of field numbers—indexes in the
table->field[]
array
of
Field
objects—for all
BLOB
fields. We simply iterate over this array, find the
corresponding
Field_blob
object, and use its
get_packed_size()
method, which
returns the number of bytes that the packed image of the actual
BLOB
field value will
need. Unlike
table>s->reclength
, which is a fixed length of the row, and does not
depend on the row content, we need to use a sizes of an actual
BLOB
field content,
unless we want to allocate 4 GB of memory for every
BLOB
field in the table up front.
if (row_buf.realloc(max_length))
return 1;