summaryrefslogtreecommitdiff
path: root/sql/records.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/records.cc')
-rw-r--r--sql/records.cc169
1 files changed, 141 insertions, 28 deletions
diff --git a/sql/records.cc b/sql/records.cc
index 817caada8e2..900eacf5943 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -38,8 +38,8 @@
static int rr_quick(READ_RECORD *info);
int rr_sequential(READ_RECORD *info);
static int rr_from_tempfile(READ_RECORD *info);
-static int rr_unpack_from_tempfile(READ_RECORD *info);
-static int rr_unpack_from_buffer(READ_RECORD *info);
+template<bool> static int rr_unpack_from_tempfile(READ_RECORD *info);
+template<bool,bool> static int rr_unpack_from_buffer(READ_RECORD *info);
int rr_from_pointers(READ_RECORD *info);
static int rr_from_cache(READ_RECORD *info);
static int init_rr_cache(THD *thd, READ_RECORD *info);
@@ -187,23 +187,24 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
bool disable_rr_cache)
{
IO_CACHE *tempfile;
- SORT_ADDON_FIELD *addon_field= filesort ? filesort->addon_field : 0;
DBUG_ENTER("init_read_record");
+ const bool using_addon_fields= filesort && filesort->using_addon_fields();
+ bool using_packed_sortkeys= filesort && filesort->using_packed_sortkeys();
+
bzero((char*) info,sizeof(*info));
info->thd=thd;
info->table=table;
- info->addon_field= addon_field;
+ info->sort_info= filesort;
if ((table->s->tmp_table == INTERNAL_TMP_TABLE) &&
- !addon_field)
+ !using_addon_fields)
(void) table->file->extra(HA_EXTRA_MMAP);
- if (addon_field)
+ if (using_addon_fields)
{
- info->rec_buf= (uchar*) filesort->addon_buf.str;
- info->ref_length= (uint)filesort->addon_buf.length;
- info->unpack= filesort->unpack;
+ info->rec_buf= filesort->addon_fields->get_addon_buf();
+ info->ref_length= filesort->addon_fields->get_addon_buf_length();
}
else
{
@@ -223,9 +224,20 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
if (tempfile && !(select && select->quick))
{
- DBUG_PRINT("info",("using rr_from_tempfile"));
- info->read_record_func=
- addon_field ? rr_unpack_from_tempfile : rr_from_tempfile;
+ if (using_addon_fields)
+ {
+ DBUG_PRINT("info",("using rr_from_tempfile"));
+ if (filesort->addon_fields->using_packed_addons())
+ info->read_record_func= rr_unpack_from_tempfile<true>;
+ else
+ info->read_record_func= rr_unpack_from_tempfile<false>;
+ }
+ else
+ {
+ DBUG_PRINT("info",("using rr_from_tempfile"));
+ info->read_record_func= rr_from_tempfile;
+ }
+
info->io_cache= tempfile;
reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
info->ref_pos=table->file->ref;
@@ -239,7 +251,7 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
and filesort->io_cache is read sequentially
*/
if (!disable_rr_cache &&
- !addon_field &&
+ !using_addon_fields &&
thd->variables.read_rnd_buff_size &&
!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
(table->db_stat & HA_READ_ONLY ||
@@ -264,16 +276,38 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
DBUG_PRINT("info",("using rr_quick"));
info->read_record_func= rr_quick;
}
- else if (filesort && filesort->record_pointers)
+ else if (filesort && filesort->has_filesort_result_in_memory())
{
DBUG_PRINT("info",("using record_pointers"));
if (unlikely(table->file->ha_rnd_init_with_error(0)))
DBUG_RETURN(1);
+
info->cache_pos= filesort->record_pointers;
- info->cache_end= (info->cache_pos+
- filesort->return_rows * info->ref_length);
- info->read_record_func=
- addon_field ? rr_unpack_from_buffer : rr_from_pointers;
+ if (using_addon_fields)
+ {
+ DBUG_PRINT("info",("using rr_unpack_from_buffer"));
+ DBUG_ASSERT(filesort->sorted_result_in_fsbuf);
+ info->unpack_counter= 0;
+
+ if (filesort->using_packed_addons())
+ {
+ info->read_record_func= using_packed_sortkeys ?
+ rr_unpack_from_buffer<true, true> :
+ rr_unpack_from_buffer<true, false>;
+ }
+ else
+ {
+ info->read_record_func= using_packed_sortkeys ?
+ rr_unpack_from_buffer<false, true> :
+ rr_unpack_from_buffer<false, false>;
+ }
+ }
+ else
+ {
+ info->cache_end= (info->cache_pos+
+ filesort->return_rows * info->ref_length);
+ info->read_record_func= rr_from_pointers;
+ }
}
else if (table->file->keyread_enabled())
{
@@ -518,7 +552,11 @@ static int rr_from_tempfile(READ_RECORD *info)
the fields values use in the result set from this buffer into their
positions in the regular record buffer.
- @param info Reference to the context including record descriptors
+ @param info Reference to the context including record
+ descriptors
+ @param Packed_addon_fields Are the addon fields packed?
+ This is a compile-time constant, to
+ avoid if (....) tests during execution.
@retval
0 Record successfully read.
@@ -526,12 +564,38 @@ static int rr_from_tempfile(READ_RECORD *info)
-1 There is no record to be read anymore.
*/
+template<bool Packed_addon_fields>
static int rr_unpack_from_tempfile(READ_RECORD *info)
{
- if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
- return -1;
- (*info->unpack)(info->addon_field, info->rec_buf,
- info->rec_buf + info->ref_length);
+ uchar *destination= info->rec_buf;
+#ifndef DBUG_OFF
+ my_off_t where= my_b_tell(info->io_cache);
+#endif
+ if (Packed_addon_fields)
+ {
+ const uint len_sz= Addon_fields::size_of_length_field;
+
+ // First read length of the record.
+ if (my_b_read(info->io_cache, destination, len_sz))
+ return -1;
+ uint res_length= Addon_fields::read_addon_length(destination);
+ DBUG_PRINT("info", ("rr_unpack from %llu to %p sz %u",
+ static_cast<ulonglong>(where),
+ destination, res_length));
+ DBUG_ASSERT(res_length > len_sz);
+ DBUG_ASSERT(info->sort_info->using_addon_fields());
+
+ // Then read the rest of the record.
+ if (my_b_read(info->io_cache, destination + len_sz, res_length - len_sz))
+ return -1; /* purecov: inspected */
+ }
+ else
+ {
+ if (my_b_read(info->io_cache, destination, info->ref_length))
+ return -1;
+ }
+
+ info->sort_info->unpack_addon_fields<Packed_addon_fields>(destination);
return 0;
}
@@ -568,7 +632,11 @@ int rr_from_pointers(READ_RECORD *info)
the fields values use in the result set from this buffer into their
positions in the regular record buffer.
- @param info Reference to the context including record descriptors
+ @param info Reference to the context including record
+ descriptors
+ @param Packed_addon_fields Are the addon fields packed?
+ This is a compile-time constant, to
+ avoid if (....) tests during execution.
@retval
0 Record successfully read.
@@ -576,13 +644,22 @@ int rr_from_pointers(READ_RECORD *info)
-1 There is no record to be read anymore.
*/
+template<bool Packed_addon_fields, bool Packed_sort_keys>
static int rr_unpack_from_buffer(READ_RECORD *info)
{
- if (info->cache_pos == info->cache_end)
+ if (info->unpack_counter == info->sort_info->return_rows)
return -1; /* End of buffer */
- (*info->unpack)(info->addon_field, info->cache_pos,
- info->cache_end);
- info->cache_pos+= info->ref_length;
+
+ uchar *record= info->sort_info->get_sorted_record(
+ static_cast<uint>(info->unpack_counter));
+
+ uint sort_length= Packed_sort_keys ?
+ Sort_keys::read_sortkey_length(record):
+ info->sort_info->get_sort_length();
+
+ uchar *plen= record + sort_length;
+ info->sort_info->unpack_addon_fields<Packed_addon_fields>(plen);
+ info->unpack_counter++;
return 0;
}
/* cacheing of records from a database */
@@ -717,3 +794,39 @@ static int rr_cmp(uchar *a,uchar *b)
return (int) a[7] - (int) b[7];
#endif
}
+
+
+/**
+ Copy (unpack) values appended to sorted fields from a buffer back to
+ their regular positions specified by the Field::ptr pointers.
+
+ @param addon_field Array of descriptors for appended fields
+ @param buff Buffer which to unpack the value from
+
+ @note
+ The function is supposed to be used only as a callback function
+ when getting field values for the sorted result set.
+
+*/
+template<bool Packed_addon_fields>
+inline void SORT_INFO::unpack_addon_fields(uchar *buff)
+{
+ SORT_ADDON_FIELD *addonf= addon_fields->begin();
+ uchar *buff_end= buff + sort_buffer_size();
+ const uchar *start_of_record= buff + addonf->offset;
+
+ for ( ; addonf != addon_fields->end() ; addonf++)
+ {
+ Field *field= addonf->field;
+ if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
+ {
+ field->set_null();
+ continue;
+ }
+ field->set_notnull();
+ if (Packed_addon_fields)
+ start_of_record= field->unpack(field->ptr, start_of_record, buff_end, 0);
+ else
+ field->unpack(field->ptr, buff + addonf->offset, buff_end, 0);
+ }
+}