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( ...@@ -4138,58 +4138,28 @@ btr_rec_free_updated_extern_fields(
} }
/*********************************************************************** /***********************************************************************
Copies an externally stored field of a record to mem heap. Parameter Copies the prefix of an externally stored field of a record. */
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 static
byte* ulint
btr_copy_externally_stored_field( btr_copy_externally_stored_field_prefix_low(
/*=============================*/ /*========================================*/
/* out: the whole field copied to heap */ /* out: bytes written to buf */
ulint* len, /* out: length of the whole field */ byte* buf, /* out: the externally stored part of
byte* data, /* in: 'internally' stored part of the the field, or a prefix of it */
field containing also the reference to ulint len, /* in: length of buf, in bytes */
the external part */
ulint zip_size,/* in: nonzero=compressed BLOB page size, ulint zip_size,/* in: nonzero=compressed BLOB page size,
zero for uncompressed BLOBs */ zero for uncompressed BLOBs */
ulint local_len,/* in: length of data */ ulint space_id,/* in: space id of the first BLOB page */
mem_heap_t* heap) /* in: mem heap */ ulint page_no,/* in: page number of the first BLOB page */
ulint offset) /* in: offset on the first BLOB page */
{ {
page_t* page; page_t* page;
ulint space_id; ulint copied_len = 0;
ulint page_no;
ulint offset;
ulint extern_len;
ulint copied_len;
byte* buf;
mtr_t mtr; mtr_t mtr;
z_stream d_stream; z_stream d_stream;
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); if (UNIV_UNLIKELY(len == 0)) {
return(0);
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(zip_size)) { if (UNIV_UNLIKELY(zip_size)) {
...@@ -4201,8 +4171,8 @@ btr_copy_externally_stored_field( ...@@ -4201,8 +4171,8 @@ btr_copy_externally_stored_field(
err = inflateInit(&d_stream); err = inflateInit(&d_stream);
ut_a(err == Z_OK); ut_a(err == Z_OK);
d_stream.next_out = buf + local_len; d_stream.next_out = buf;
d_stream.avail_out = extern_len; d_stream.avail_out = len;
d_stream.avail_in = 0; d_stream.avail_in = 0;
} }
...@@ -4245,6 +4215,9 @@ btr_copy_externally_stored_field( ...@@ -4245,6 +4215,9 @@ btr_copy_externally_stored_field(
err = inflate(&d_stream, Z_NO_FLUSH); err = inflate(&d_stream, Z_NO_FLUSH);
switch (err) { switch (err) {
case Z_OK: case Z_OK:
if (!d_stream.avail_out) {
goto end_of_blob;
}
break; break;
case Z_STREAM_END: case Z_STREAM_END:
if (next_page_no == FIL_NULL) { if (next_page_no == FIL_NULL) {
...@@ -4260,11 +4233,8 @@ btr_copy_externally_stored_field( ...@@ -4260,11 +4233,8 @@ btr_copy_externally_stored_field(
" page %lu space %lu returned %d\n", " page %lu space %lu returned %d\n",
(ulong) page_no, (ulong) space_id, (ulong) page_no, (ulong) space_id,
err); err);
err_exit: case Z_BUF_ERROR:
mtr_commit(&mtr); goto end_of_blob;
inflateEnd(&d_stream);
*len = 0;
return(buf);
} }
if (next_page_no == FIL_NULL) { if (next_page_no == FIL_NULL) {
...@@ -4276,23 +4246,18 @@ btr_copy_externally_stored_field( ...@@ -4276,23 +4246,18 @@ btr_copy_externally_stored_field(
" page %lu space %lu\n", " page %lu space %lu\n",
(ulong) page_no, (ulong) page_no,
(ulong) space_id); (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: end_of_blob:
mtr_commit(&mtr); mtr_commit(&mtr);
ut_a(!d_stream.avail_out);
inflateEnd(&d_stream); inflateEnd(&d_stream);
ut_ad(buf + local_len + d_stream.total_out return(d_stream.total_out);
== d_stream.next_out);
*len = d_stream.next_out - buf;
return(buf);
} }
mtr_commit(&mtr); mtr_commit(&mtr);
...@@ -4307,21 +4272,19 @@ btr_copy_externally_stored_field( ...@@ -4307,21 +4272,19 @@ btr_copy_externally_stored_field(
= page + offset; = page + offset;
ulint part_len ulint part_len
= btr_blob_get_part_len(blob_header); = btr_blob_get_part_len(blob_header);
ulint copy_len
= ut_max(part_len, len - copied_len);
memcpy(buf + copied_len, memcpy(buf + copied_len,
blob_header + BTR_BLOB_HDR_SIZE, part_len); blob_header + BTR_BLOB_HDR_SIZE, copy_len);
copied_len += part_len; copied_len += copy_len;
page_no = btr_blob_get_next_page_no(blob_header); page_no = btr_blob_get_next_page_no(blob_header);
mtr_commit(&mtr); mtr_commit(&mtr);
if (page_no == FIL_NULL) { if (page_no == FIL_NULL || copy_len != part_len) {
ut_a(copied_len == local_len + extern_len); return(copied_len);
*len = copied_len;
return(buf);
} }
/* On other BLOB pages except the first the BLOB header /* On other BLOB pages except the first the BLOB header
...@@ -4329,11 +4292,113 @@ btr_copy_externally_stored_field( ...@@ -4329,11 +4292,113 @@ btr_copy_externally_stored_field(
offset = FIL_PAGE_DATA; 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. */ Copies an externally stored field of a record to mem heap. */
......
...@@ -500,6 +500,24 @@ btr_free_externally_stored_field( ...@@ -500,6 +500,24 @@ btr_free_externally_stored_field(
data an an X-latch to the index data an an X-latch to the index
tree */ 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. */ Copies an externally stored field of a record to mem heap. */
byte* byte*
......
...@@ -50,6 +50,37 @@ to que_run_threads: this is to allow canceling runaway queries */ ...@@ -50,6 +50,37 @@ to que_run_threads: this is to allow canceling runaway queries */
#define SEL_EXHAUSTED 1 #define SEL_EXHAUSTED 1
#define SEL_RETRY 2 #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 Returns TRUE if the user-defined column values in a secondary index record
are alphabetically the same as the corresponding columns in the clustered are alphabetically the same as the corresponding columns in the clustered
...@@ -72,7 +103,6 @@ row_sel_sec_rec_is_for_clust_rec( ...@@ -72,7 +103,6 @@ row_sel_sec_rec_is_for_clust_rec(
byte* sec_field; byte* sec_field;
ulint sec_len; ulint sec_len;
byte* clust_field; byte* clust_field;
ulint clust_len;
ulint n; ulint n;
ulint i; ulint i;
mem_heap_t* heap = NULL; mem_heap_t* heap = NULL;
...@@ -95,26 +125,47 @@ row_sel_sec_rec_is_for_clust_rec( ...@@ -95,26 +125,47 @@ row_sel_sec_rec_is_for_clust_rec(
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
const dict_field_t* ifield; const dict_field_t* ifield;
const dict_col_t* col; const dict_col_t* col;
ulint clust_pos;
ulint clust_len;
ulint len;
ifield = dict_index_get_nth_field(sec_index, i); ifield = dict_index_get_nth_field(sec_index, i);
col = dict_field_get_col(ifield); col = dict_field_get_col(ifield);
clust_pos = dict_col_get_clust_pos(col, clust_index);
clust_field = rec_get_nth_field( clust_field = rec_get_nth_field(
clust_rec, clust_offs, clust_rec, clust_offs, clust_pos, &clust_len);
dict_col_get_clust_pos(col, clust_index), &clust_len);
sec_field = rec_get_nth_field(sec_rec, sec_offs, i, &sec_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, col->prtype, col->mbminlen, col->mbmaxlen,
ifield->prefix_len, ifield->prefix_len, len, (char*) clust_field);
clust_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, if (0 != cmp_data_data(col->mtype, col->prtype,
clust_field, clust_len, clust_field, len,
sec_field, sec_len)) { sec_field, sec_len)) {
inequal:
is_equal = FALSE; is_equal = FALSE;
goto func_exit; 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