summaryrefslogtreecommitdiff
path: root/sql/item_sum.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r--sql/item_sum.cc258
1 files changed, 137 insertions, 121 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 8d025891877..c79e909658c 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -30,7 +30,7 @@ Item_sum::Item_sum(List<Item> &list)
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
{
uint i=0;
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
while ((item=li++))
@@ -790,74 +790,71 @@ String *Item_std_field::val_str(String *str)
static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
{
- return memcmp(key1, key2, (int)arg);
+ return memcmp(key1, key2, (int) arg);
}
static int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
{
- return my_sortcmp(key1, key2, (int)arg);
+ return my_sortcmp(key1, key2, (int) arg);
}
-// did not make this one static - at least gcc gets confused when
-// I try to declare a static function as a friend. If you can figure
-// out the syntax to make a static function a friend, make this one
-// static
+/*
+ Did not make this one static - at least gcc gets confused when
+ I try to declare a static function as a friend. If you can figure
+ out the syntax to make a static function a friend, make this one
+ static
+*/
+
int composite_key_cmp(void* arg, byte* key1, byte* key2)
{
Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
- Field** field = item->table->field, **field_end;
- field_end = field + item->table->fields;
- for(; field < field_end; ++field)
- {
- int res;
- Field* f = *field;
- int len = f->pack_length();
- switch((*field)->type())
- {
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
- res = f->key_cmp(key1, key2);
- break;
- default:
- res = memcmp(key1, key2, len);
- break;
- }
- if(res)
- return res;
- key1 += len;
- key2 += len;
- }
+ Field **field = item->table->field;
+ Field **field_end= field + item->table->fields;
+ uint32 *lengths=item->field_lengths;
+ for (; field < field_end; ++field)
+ {
+ Field* f = *field;
+ int len = *lengths++;
+ int res = f->key_cmp(key1, key2);
+ if (res)
+ return res;
+ key1 += len;
+ key2 += len;
+ }
return 0;
}
-// helper function for walking the tree when we dump it to MyISAM -
-// tree_walk will call it for each
-// leaf
+/*
+ helper function for walking the tree when we dump it to MyISAM -
+ tree_walk will call it for each leaf
+*/
int dump_leaf(byte* key, uint32 count __attribute__((unused)),
Item_sum_count_distinct* item)
{
char* buf = item->table->record[0];
int error;
- // the first item->rec_offset bytes are taken care of with
- // restore_record(table,2) in setup()
+ /*
+ The first item->rec_offset bytes are taken care of with
+ restore_record(table,2) in setup()
+ */
memcpy(buf + item->rec_offset, key, item->tree.size_of_element);
if ((error = item->table->file->write_row(buf)))
{
- if (error != HA_ERR_FOUND_DUPP_KEY &&
- error != HA_ERR_FOUND_DUPP_UNIQUE)
- return 1;
+ if (error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE)
+ return 1;
}
-
return 0;
}
+
Item_sum_count_distinct::~Item_sum_count_distinct()
{
if (table)
free_tmp_table(current_thd, table);
delete tmp_table_param;
- if(use_tree)
+ if (use_tree)
delete_tree(&tree);
}
@@ -895,91 +892,108 @@ bool Item_sum_count_distinct::setup(THD *thd)
tmp_table_param->cleanup();
}
if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
- 0, 0, current_lex->select->options | thd->options)))
+ 0, 0,
+ current_lex->select->options | thd->options)))
return 1;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
- if(table->db_type == DB_TYPE_HEAP) // no blobs, otherwise it would be
- // MyISAM
- {
- qsort_cmp2 compare_key;
- void* cmp_arg;
- int key_len;
+ // no blobs, otherwise it would be MyISAM
+ if (table->db_type == DB_TYPE_HEAP)
+ {
+ qsort_cmp2 compare_key;
+ void* cmp_arg;
+ int key_len;
- // to make things easier for dump_leaf if we ever have to dump to
- // MyISAM
- restore_record(table,2);
+ // to make things easier for dump_leaf if we ever have to dump to MyISAM
+ restore_record(table,2);
- if(table->fields == 1) // if we have only one field, which is
- // the most common use of count(distinct), it is much faster
- // to use a simpler key compare method that can take advantage
- // of not having to worry about other fields
- {
- Field* field = table->field[0];
- switch(field->type())
- {
- // if we have a string, we must take care of charsets
- // and case sensitivity
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
- compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp:
- simple_str_key_cmp);
- break;
- default: // since at this point we cannot have blobs
- // anything else can be compared with memcmp
- compare_key = (qsort_cmp2)simple_raw_key_cmp;
- break;
- }
- cmp_arg = (void*)(key_len = field->pack_length());
- rec_offset = 1;
- }
- else // too bad, cannot cheat - there is more than one field
- {
- bool all_binary = 1;
- Field** field, **field_end;
- field_end = (field = table->field) + table->fields;
- for(key_len = 0; field < field_end; ++field)
- {
- key_len += (*field)->pack_length();
- if(!(*field)->binary())
- all_binary = 0;
- }
- rec_offset = table->reclength - key_len;
- if(all_binary)
- {
- compare_key = (qsort_cmp2)simple_raw_key_cmp;
- cmp_arg = (void*)key_len;
- }
- else
- {
- compare_key = (qsort_cmp2)composite_key_cmp ;
- cmp_arg = (void*)this;
- }
- }
-
- init_tree(&tree, min(max_heap_table_size, sortbuff_size/16), 0,
- key_len, compare_key, 0, NULL, cmp_arg);
- use_tree = 1;
-
- // the only time key_len could be 0 is if someone does
- // count(distinct) on a char(0) field - stupid thing to do,
- // but this has to be handled - otherwise someone can crash
- // the server with a DoS attack
- max_elements_in_tree = (key_len) ? max_heap_table_size/key_len :
- 1;
+ if (table->fields == 1)
+ {
+ /*
+ If we have only one field, which is the most common use of
+ count(distinct), it is much faster to use a simpler key
+ compare method that can take advantage of not having to worry
+ about other fields
+ */
+ Field* field = table->field[0];
+ switch(field->type())
+ {
+ /*
+ If we have a string, we must take care of charsets and case
+ sensitivity
+ */
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_VAR_STRING:
+ compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp:
+ simple_str_key_cmp);
+ break;
+ default:
+ /*
+ Since at this point we cannot have blobs anything else can
+ be compared with memcmp
+ */
+ compare_key = (qsort_cmp2)simple_raw_key_cmp;
+ break;
+ }
+ cmp_arg = (void*)(key_len = field->pack_length());
+ rec_offset = 1;
}
-
+ else // too bad, cannot cheat - there is more than one field
+ {
+ bool all_binary = 1;
+ Field** field, **field_end;
+ field_end = (field = table->field) + table->fields;
+ uint32 *lengths;
+ if (!(field_lengths=
+ (uint32*) thd->alloc(sizeof(uint32) * table->fields)))
+ return 1;
+
+ for (key_len = 0, lengths=field_lengths; field < field_end; ++field)
+ {
+ uint32 length= (*field)->pack_length();
+ key_len += length;
+ *lengths++ = length;
+ if (!(*field)->binary())
+ all_binary = 0; // Can't break loop here
+ }
+ rec_offset = table->reclength - key_len;
+ if (all_binary)
+ {
+ compare_key = (qsort_cmp2)simple_raw_key_cmp;
+ cmp_arg = (void*)key_len;
+ }
+ else
+ {
+ compare_key = (qsort_cmp2) composite_key_cmp ;
+ cmp_arg = (void*)this;
+ }
+ }
+
+ init_tree(&tree, min(max_heap_table_size, sortbuff_size/16), 0,
+ key_len, compare_key, 0, NULL, cmp_arg);
+ use_tree = 1;
+
+ /*
+ The only time key_len could be 0 is if someone does
+ count(distinct) on a char(0) field - stupid thing to do,
+ but this has to be handled - otherwise someone can crash
+ the server with a DoS attack
+ */
+ max_elements_in_tree = ((key_len) ? max_heap_table_size/key_len :
+ 1);
+ }
return 0;
}
+
int Item_sum_count_distinct::tree_to_myisam()
{
- if(create_myisam_from_heap(table, tmp_table_param,
- HA_ERR_RECORD_FILE_FULL, 1) ||
- tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this,
- left_root_right))
+ if (create_myisam_from_heap(table, tmp_table_param,
+ HA_ERR_RECORD_FILE_FULL, 1) ||
+ tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this,
+ left_root_right))
return 1;
delete_tree(&tree);
use_tree = 0;
@@ -1011,18 +1025,20 @@ bool Item_sum_count_distinct::add()
if ((*field)->is_real_null(0))
return 0; // Don't count NULL
- if(use_tree)
+ if (use_tree)
+ {
+ /*
+ If the tree got too big, convert to MyISAM, otherwise insert into the
+ tree.
+ */
+ if (tree.elements_in_tree > max_elements_in_tree)
{
- // if the tree got too big, convert to MyISAM, otherwise
- // insert into the tree
- if(tree.elements_in_tree > max_elements_in_tree)
- {
- if(tree_to_myisam())
- return 1;
- }
- else if(!tree_insert(&tree, table->record[0] + rec_offset, 0))
+ if(tree_to_myisam())
return 1;
}
+ else if (!tree_insert(&tree, table->record[0] + rec_offset, 0))
+ return 1;
+ }
else if ((error=table->file->write_row(table->record[0])))
{
if (error != HA_ERR_FOUND_DUPP_KEY &&
@@ -1039,7 +1055,7 @@ longlong Item_sum_count_distinct::val_int()
{
if (!table) // Empty query
return LL(0);
- if(use_tree)
+ if (use_tree)
return tree.elements_in_tree;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
return table->file->records;