summaryrefslogtreecommitdiff
path: root/sql/filesort.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/filesort.cc')
-rw-r--r--sql/filesort.cc217
1 files changed, 143 insertions, 74 deletions
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 12b17846fe4..df84787372d 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -44,6 +44,7 @@ static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
static void make_sortkey(SORTPARAM *param,uchar *to, byte *ref_pos);
+static void register_used_fields(SORTPARAM *param);
static int merge_index(SORTPARAM *param,uchar *sort_buffer,
BUFFPEK *buffpek,
uint maxbuffer,IO_CACHE *tempfile,
@@ -66,11 +67,11 @@ static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
table Table to sort
sortorder How to sort the table
s_length Number of elements in sortorder
- select condition to apply to the rows
- special Not used.
- (This could be used to sort the rows pointed on by
- select->file)
- examined_rows Store number of examined rows here
+ select Condition to apply to the rows
+ ha_maxrows Return only this many rows
+ sort_positions Set to 1 if we want to force sorting by position
+ (Needed by UPDATE/INSERT or ALTER TABLE)
+ examined_rows Store number of examined rows here
IMPLEMENTATION
Creates a set of pointers that can be used to read the rows
@@ -81,6 +82,10 @@ static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
Before calling filesort, one must have done
table->file->info(HA_STATUS_VARIABLE)
+ NOTES
+ If we sort by position (like if sort_positions is 1) filesort() will
+ call table->prepare_for_position().
+
RETURN
HA_POS_ERROR Error
# Number of rows
@@ -92,7 +97,8 @@ static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
*/
ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
- SQL_SELECT *select, ha_rows max_rows, ha_rows *examined_rows)
+ SQL_SELECT *select, ha_rows max_rows,
+ bool sort_positions, ha_rows *examined_rows)
{
int error;
ulong memavl, min_sort_memory;
@@ -129,8 +135,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
param.ref_length= table->file->ref_length;
param.addon_field= 0;
param.addon_length= 0;
- if (!(table->file->table_flags() & HA_FAST_KEY_READ) &&
- !table->fulltext_searched)
+ if (!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
+ !table->fulltext_searched && !sort_positions)
{
/*
Get the descriptors of all fields whose values are appended
@@ -176,7 +182,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (select && select->quick && select->quick->records > 0L)
{
records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
- table->file->records)+EXTRA_RECORDS;
+ table->file->stats.records)+EXTRA_RECORDS;
selected_records_file=0;
}
else
@@ -431,8 +437,11 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
TABLE *sort_form;
volatile THD::killed_state *killed= &current_thd->killed;
handler *file;
+ MY_BITMAP *save_read_set, *save_write_set;
DBUG_ENTER("find_all_keys");
- DBUG_PRINT("info",("using: %s",(select?select->quick?"ranges":"where":"every row")));
+ DBUG_PRINT("info",("using: %s",
+ (select ? select->quick ? "ranges" : "where":
+ "every row")));
idx=indexpos=0;
error=quick_select=0;
@@ -442,7 +451,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
ref_pos= ref_buff;
quick_select=select && select->quick;
record=0;
- flag= ((!indexfile && file->table_flags() & HA_REC_NOT_IN_SEQ)
+ flag= ((!indexfile && file->ha_table_flags() & HA_REC_NOT_IN_SEQ)
|| quick_select);
if (indexfile || flag)
ref_pos= &file->ref[0];
@@ -464,6 +473,19 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
select, 1, 1);
}
+ /* Remember original bitmaps */
+ save_read_set= sort_form->read_set;
+ save_write_set= sort_form->write_set;
+ /* Set up temporary column read map for columns used by sort */
+ bitmap_clear_all(&sort_form->tmp_set);
+ /* Temporary set for register_used_fields and register_field_in_read_map */
+ sort_form->read_set= &sort_form->tmp_set;
+ register_used_fields(param);
+ if (select && select->cond)
+ select->cond->walk(&Item::register_field_in_read_map, 1,
+ (byte*) sort_form);
+ sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
+
for (;;)
{
if (quick_select)
@@ -542,6 +564,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
file->ha_rnd_end();
}
+ /* Signal we should use orignal column read and write maps */
+ sort_form->column_bitmaps_set(save_read_set, save_write_set);
+
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (error != HA_ERR_END_OF_FILE)
{
@@ -675,62 +700,70 @@ static void make_sortkey(register SORTPARAM *param,
switch (sort_field->result_type) {
case STRING_RESULT:
{
- CHARSET_INFO *cs=item->collation.collation;
- char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
- int diff;
- uint sort_field_length;
-
- if (maybe_null)
- *to++=1;
- /* All item->str() to use some extra byte for end null.. */
- String tmp((char*) to,sort_field->length+4,cs);
- String *res= item->str_result(&tmp);
- if (!res)
- {
- if (maybe_null)
- bzero((char*) to-1,sort_field->length+1);
- else
- {
- DBUG_PRINT("warning",
- ("Got null on something that shouldn't be null"));
- bzero((char*) to,sort_field->length); // Avoid crash
- }
- break;
- }
- length= res->length();
- sort_field_length= sort_field->length - sort_field->suffix_length;
- diff=(int) (sort_field_length - length);
- if (diff < 0)
- {
- diff=0; /* purecov: inspected */
- length= sort_field_length;
- }
- if (sort_field->suffix_length)
- {
- /* Store length last in result_string */
- store_length(to + sort_field_length, length,
- sort_field->suffix_length);
- }
- if (sort_field->need_strxnfrm)
+ CHARSET_INFO *cs=item->collation.collation;
+ char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
+ int diff;
+ uint sort_field_length;
+
+ if (maybe_null)
+ *to++=1;
+ /* All item->str() to use some extra byte for end null.. */
+ String tmp((char*) to,sort_field->length+4,cs);
+ String *res= item->str_result(&tmp);
+ if (!res)
+ {
+ if (maybe_null)
+ bzero((char*) to-1,sort_field->length+1);
+ else
{
- char *from=(char*) res->ptr();
- uint tmp_length;
- if ((unsigned char *)from == to)
- {
- set_if_smaller(length,sort_field->length);
- memcpy(param->tmp_buffer,from,length);
- from=param->tmp_buffer;
- }
- tmp_length= my_strnxfrm(cs,to,sort_field->length,
- (unsigned char *) from, length);
- DBUG_ASSERT(tmp_length == sort_field->length);
+ /* purecov: begin deadcode */
+ /*
+ This should only happen during extreme conditions if we run out
+ of memory or have an item marked not null when it can be null.
+ This code is here mainly to avoid a hard crash in this case.
+ */
+ DBUG_ASSERT(0);
+ DBUG_PRINT("warning",
+ ("Got null on something that shouldn't be null"));
+ bzero((char*) to,sort_field->length); // Avoid crash
+ /* purecov: end */
}
- else
+ break;
+ }
+ length= res->length();
+ sort_field_length= sort_field->length - sort_field->suffix_length;
+ diff=(int) (sort_field_length - length);
+ if (diff < 0)
+ {
+ diff=0;
+ length= sort_field_length;
+ }
+ if (sort_field->suffix_length)
+ {
+ /* Store length last in result_string */
+ store_length(to + sort_field_length, length,
+ sort_field->suffix_length);
+ }
+ if (sort_field->need_strxnfrm)
+ {
+ char *from=(char*) res->ptr();
+ uint tmp_length;
+ if ((uchar*) from == to)
{
- my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
- cs->cset->fill(cs, (char *)to+length,diff,fill_char);
+ set_if_smaller(length,sort_field->length);
+ memcpy(param->tmp_buffer,from,length);
+ from=param->tmp_buffer;
}
- break;
+ tmp_length= my_strnxfrm(cs,to,sort_field->length,
+ (uchar*) from, length);
+ DBUG_ASSERT(tmp_length == sort_field->length);
+ }
+ else
+ {
+ my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
+ cs->cset->fill(cs, (char *)to+length,diff,fill_char);
+ }
+ break;
}
case INT_RESULT:
{
@@ -873,6 +906,49 @@ static void make_sortkey(register SORTPARAM *param,
return;
}
+
+/*
+ Register fields used by sorting in the sorted table's read set
+*/
+
+static void register_used_fields(SORTPARAM *param)
+{
+ reg1 SORT_FIELD *sort_field;
+ TABLE *table=param->sort_form;
+ MY_BITMAP *bitmap= table->read_set;
+
+ for (sort_field= param->local_sortorder ;
+ sort_field != param->end ;
+ sort_field++)
+ {
+ Field *field;
+ if ((field= sort_field->field))
+ {
+ if (field->table == table)
+ bitmap_set_bit(bitmap, field->field_index);
+ }
+ else
+ { // Item
+ sort_field->item->walk(&Item::register_field_in_read_map, 1,
+ (byte *) table);
+ }
+ }
+
+ if (param->addon_field)
+ {
+ SORT_ADDON_FIELD *addonf= param->addon_field;
+ Field *field;
+ for ( ; (field= addonf->field) ; addonf++)
+ bitmap_set_bit(bitmap, field->field_index);
+ }
+ else
+ {
+ /* Save filepos last */
+ table->prepare_for_position();
+ }
+}
+
+
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
FILESORT_INFO *table_sort)
{
@@ -1382,7 +1458,8 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
uint length= 0;
uint fields= 0;
uint null_fields= 0;
- query_id_t query_id= thd->query_id;
+ MY_BITMAP *read_set= (*ptabfield)->table->read_set;
+
/*
If there is a reference to a field in the query add it
to the the set of appended fields.
@@ -1394,17 +1471,9 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
*/
*plength= 0;
- /*
- The following statement is added to avoid sorting in alter_table.
- The fact is the filter 'field->query_id != thd->query_id'
- doesn't work for alter table
- */
- if (thd->lex->sql_command != SQLCOM_SELECT &&
- thd->lex->sql_command != SQLCOM_INSERT_SELECT)
- return 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
- if (field->query_id != query_id)
+ if (!bitmap_is_set(read_set, field->field_index))
continue;
if (field->flags & BLOB_FLAG)
return 0;
@@ -1427,7 +1496,7 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
null_fields= 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
- if (field->query_id != thd->query_id)
+ if (!bitmap_is_set(read_set, field->field_index))
continue;
addonf->field= field;
addonf->offset= length;