Commit c66a0754 authored by marko's avatar marko

branches/zip: Implement the ability to fetch a prefix of an externally

stored column.  This is the first part of fixing Bug #22496.

btr_copy_externally_stored_field_prefix(): New function.

btr_copy_externally_stored_field(): Split to
btr_copy_externally_stored_field_prefix_low().

row_sel_sec_rec_is_for_blob(): New function, used by
row_sel_sec_rec_is_for_clust_rec() in selects via
a secondary index.
parent 8e59e994
......@@ -4138,58 +4138,28 @@ btr_rec_free_updated_extern_fields(
}
/***********************************************************************
Copies an externally stored field of a record to mem heap. Parameter
data contains a pointer to 'internally' stored part of the field:
possibly some data, and the reference to the externally stored part in
the last BTR_EXTERN_FIELD_REF_SIZE bytes of data. */
Copies the prefix of an externally stored field of a record. */
static
byte*
btr_copy_externally_stored_field(
/*=============================*/
/* out: the whole field copied to heap */
ulint* len, /* out: length of the whole field */
byte* data, /* in: 'internally' stored part of the
field containing also the reference to
the external part */
ulint
btr_copy_externally_stored_field_prefix_low(
/*========================================*/
/* out: bytes written to buf */
byte* buf, /* out: the externally stored part of
the field, or a prefix of it */
ulint len, /* in: length of buf, in bytes */
ulint zip_size,/* in: nonzero=compressed BLOB page size,
zero for uncompressed BLOBs */
ulint local_len,/* in: length of data */
mem_heap_t* heap) /* in: mem heap */
ulint space_id,/* in: space id of the first BLOB page */
ulint page_no,/* in: page number of the first BLOB page */
ulint offset) /* in: offset on the first BLOB page */
{
page_t* page;
ulint space_id;
ulint page_no;
ulint offset;
ulint extern_len;
ulint copied_len;
byte* buf;
ulint copied_len = 0;
mtr_t mtr;
z_stream d_stream;
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
/* Currently a BLOB cannot be bigger than 4 GB; we
leave the 4 upper bytes in the length field unused */
extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
buf = mem_heap_alloc(heap, local_len + extern_len);
memcpy(buf, data, local_len);
copied_len = local_len;
if (UNIV_UNLIKELY(extern_len == 0)) {
*len = copied_len;
return(buf);
if (UNIV_UNLIKELY(len == 0)) {
return(0);
}
if (UNIV_UNLIKELY(zip_size)) {
......@@ -4201,8 +4171,8 @@ btr_copy_externally_stored_field(
err = inflateInit(&d_stream);
ut_a(err == Z_OK);
d_stream.next_out = buf + local_len;
d_stream.avail_out = extern_len;
d_stream.next_out = buf;
d_stream.avail_out = len;
d_stream.avail_in = 0;
}
......@@ -4245,6 +4215,9 @@ btr_copy_externally_stored_field(
err = inflate(&d_stream, Z_NO_FLUSH);
switch (err) {
case Z_OK:
if (!d_stream.avail_out) {
goto end_of_blob;
}
break;
case Z_STREAM_END:
if (next_page_no == FIL_NULL) {
......@@ -4260,11 +4233,8 @@ inflate_error:
" page %lu space %lu returned %d\n",
(ulong) page_no, (ulong) space_id,
err);
err_exit:
mtr_commit(&mtr);
inflateEnd(&d_stream);
*len = 0;
return(buf);
case Z_BUF_ERROR:
goto end_of_blob;
}
if (next_page_no == FIL_NULL) {
......@@ -4276,23 +4246,18 @@ err_exit:
" page %lu space %lu\n",
(ulong) page_no,
(ulong) space_id);
goto err_exit;
} else {
err = inflate(&d_stream, Z_FINISH);
if (UNIV_UNLIKELY
(err != Z_STREAM_END)) {
goto inflate_error;
}
}
err = inflate(&d_stream, Z_FINISH);
if (UNIV_UNLIKELY(err != Z_STREAM_END)) {
goto inflate_error;
}
end_of_blob:
mtr_commit(&mtr);
ut_a(!d_stream.avail_out);
inflateEnd(&d_stream);
ut_ad(buf + local_len + d_stream.total_out
== d_stream.next_out);
*len = d_stream.next_out - buf;
return(buf);
return(d_stream.total_out);
}
mtr_commit(&mtr);
......@@ -4307,21 +4272,19 @@ end_of_blob:
= page + offset;
ulint part_len
= btr_blob_get_part_len(blob_header);
ulint copy_len
= ut_max(part_len, len - copied_len);
memcpy(buf + copied_len,
blob_header + BTR_BLOB_HDR_SIZE, part_len);
copied_len += part_len;
blob_header + BTR_BLOB_HDR_SIZE, copy_len);
copied_len += copy_len;
page_no = btr_blob_get_next_page_no(blob_header);
mtr_commit(&mtr);
if (page_no == FIL_NULL) {
ut_a(copied_len == local_len + extern_len);
*len = copied_len;
return(buf);
if (page_no == FIL_NULL || copy_len != part_len) {
return(copied_len);
}
/* On other BLOB pages except the first the BLOB header
......@@ -4329,11 +4292,113 @@ end_of_blob:
offset = FIL_PAGE_DATA;
ut_a(copied_len < local_len + extern_len);
ut_ad(copied_len <= len);
}
}
}
/***********************************************************************
Copies the prefix of an externally stored field of a record. Parameter
data contains a pointer to 'internally' stored part of the field:
possibly some data, and the reference to the externally stored part in
the last BTR_EXTERN_FIELD_REF_SIZE bytes of data. */
ulint
btr_copy_externally_stored_field_prefix(
/*====================================*/
/* out: the length of the copied field */
byte* buf, /* out: the field, or a prefix of it */
ulint len, /* in: length of buf, in bytes */
ulint zip_size,/* in: nonzero=compressed BLOB page size,
zero for uncompressed BLOBs */
const byte* data, /* in: 'internally' stored part of the
field containing also the reference to
the external part */
ulint local_len)/* in: length of data, in bytes */
{
ulint space_id;
ulint page_no;
ulint offset;
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
if (UNIV_UNLIKELY(local_len >= len)) {
memcpy(buf, data, len);
return(len);
}
memcpy(buf, data, local_len);
data += local_len;
space_id = mach_read_from_4((byte*) data + BTR_EXTERN_SPACE_ID);
page_no = mach_read_from_4((byte*) data + BTR_EXTERN_PAGE_NO);
offset = mach_read_from_4((byte*) data + BTR_EXTERN_OFFSET);
return(local_len
+ btr_copy_externally_stored_field_prefix_low(buf + local_len,
len - local_len,
zip_size,
space_id, page_no,
offset));
}
/***********************************************************************
Copies an externally stored field of a record to mem heap. Parameter
data contains a pointer to 'internally' stored part of the field:
possibly some data, and the reference to the externally stored part in
the last BTR_EXTERN_FIELD_REF_SIZE bytes of data. */
static
byte*
btr_copy_externally_stored_field(
/*=============================*/
/* out: the whole field copied to heap */
ulint* len, /* out: length of the whole field */
byte* data, /* in: 'internally' stored part of the
field containing also the reference to
the external part */
ulint zip_size,/* in: nonzero=compressed BLOB page size,
zero for uncompressed BLOBs */
ulint local_len,/* in: length of data */
mem_heap_t* heap) /* in: mem heap */
{
ulint space_id;
ulint page_no;
ulint offset;
ulint extern_len;
byte* buf;
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
/* Currently a BLOB cannot be bigger than 4 GB; we
leave the 4 upper bytes in the length field unused */
extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
buf = mem_heap_alloc(heap, local_len + extern_len);
memcpy(buf, data, local_len);
*len = local_len
+ btr_copy_externally_stored_field_prefix_low(buf + local_len,
extern_len,
zip_size,
space_id,
page_no, offset);
return(buf);
}
/***********************************************************************
Copies an externally stored field of a record to mem heap. */
......
......@@ -500,6 +500,24 @@ btr_free_externally_stored_field(
data an an X-latch to the index
tree */
/***********************************************************************
Copies the prefix of an externally stored field of a record. Parameter
data contains a pointer to 'internally' stored part of the field:
possibly some data, and the reference to the externally stored part in
the last BTR_EXTERN_FIELD_REF_SIZE bytes of data. */
ulint
btr_copy_externally_stored_field_prefix(
/*====================================*/
/* out: the length of the copied field */
byte* buf, /* out: the field, or a prefix of it */
ulint len, /* in: length of buf, in bytes */
ulint zip_size,/* in: nonzero=compressed BLOB page size,
zero for uncompressed BLOBs */
const byte* data, /* in: 'internally' stored part of the
field containing also the reference to
the external part */
ulint local_len);/* in: length of data, in bytes */
/***********************************************************************
Copies an externally stored field of a record to mem heap. */
byte*
......
......@@ -50,6 +50,37 @@ to que_run_threads: this is to allow canceling runaway queries */
#define SEL_EXHAUSTED 1
#define SEL_RETRY 2
/************************************************************************
Returns TRUE if the user-defined column in a secondary index record
is alphabetically the same as the corresponding BLOB column in the clustered
index record.
NOTE: the comparison is NOT done as a binary comparison, but character
fields are compared with collation! */
static
ibool
row_sel_sec_rec_is_for_blob(
/*========================*/
/* out: TRUE if the columns are equal */
ulint mtype, /* in: main type */
ulint prtype, /* in: precise type */
byte* clust_field, /* in: the locally stored part of
the clustered index column, including
the BLOB pointer */
ulint clust_len, /* in: length of clust_field */
byte* sec_field, /* in: column in secondary index */
ulint sec_len, /* in: length of sec_field */
ulint zip_size) /* in: compressed page size, or 0 */
{
ulint len;
byte buf[DICT_MAX_INDEX_COL_LEN];
len = btr_copy_externally_stored_field_prefix(buf, sizeof buf,
zip_size,
clust_field, clust_len);
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
}
/************************************************************************
Returns TRUE if the user-defined column values in a secondary index record
are alphabetically the same as the corresponding columns in the clustered
......@@ -72,7 +103,6 @@ row_sel_sec_rec_is_for_clust_rec(
byte* sec_field;
ulint sec_len;
byte* clust_field;
ulint clust_len;
ulint n;
ulint i;
mem_heap_t* heap = NULL;
......@@ -95,26 +125,47 @@ row_sel_sec_rec_is_for_clust_rec(
for (i = 0; i < n; i++) {
const dict_field_t* ifield;
const dict_col_t* col;
ulint clust_pos;
ulint clust_len;
ulint len;
ifield = dict_index_get_nth_field(sec_index, i);
col = dict_field_get_col(ifield);
clust_pos = dict_col_get_clust_pos(col, clust_index);
clust_field = rec_get_nth_field(
clust_rec, clust_offs,
dict_col_get_clust_pos(col, clust_index), &clust_len);
clust_rec, clust_offs, clust_pos, &clust_len);
sec_field = rec_get_nth_field(sec_rec, sec_offs, i, &sec_len);
if (ifield->prefix_len > 0 && clust_len != UNIV_SQL_NULL) {
len = clust_len;
if (ifield->prefix_len > 0 && len != UNIV_SQL_NULL) {
clust_len = dtype_get_at_most_n_mbchars(
if (rec_offs_nth_extern(clust_offs, clust_pos)) {
len -= BTR_EXTERN_FIELD_REF_SIZE;
}
len = dtype_get_at_most_n_mbchars(
col->prtype, col->mbminlen, col->mbmaxlen,
ifield->prefix_len,
clust_len, (char*) clust_field);
ifield->prefix_len, len, (char*) clust_field);
if (rec_offs_nth_extern(clust_offs, clust_pos)
&& len < sec_len) {
if (!row_sel_sec_rec_is_for_blob(
col->mtype, col->prtype,
clust_field, clust_len,
sec_field, sec_len,
dict_table_zip_size(
clust_index->table))) {
goto inequal;
}
}
}
if (0 != cmp_data_data(col->mtype, col->prtype,
clust_field, clust_len,
clust_field, len,
sec_field, sec_len)) {
inequal:
is_equal = FALSE;
goto func_exit;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment