diff options
Diffstat (limited to 'sql/records.cc')
-rw-r--r-- | sql/records.cc | 169 |
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); + } +} |