summaryrefslogtreecommitdiff
path: root/sql/sql_statistics.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_statistics.cc')
-rw-r--r--sql/sql_statistics.cc202
1 files changed, 177 insertions, 25 deletions
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 7b600bd45c4..85eb5630418 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -1517,6 +1517,41 @@ public:
}
};
+
+/*
+ @brief
+ Get the offset to the value for the field in the buffer
+
+ @param
+ field Field structure
+
+ @retval
+ offset of the value from the start of the buffer
+*/
+
+uint get_offset_to_value(Field *field)
+{
+ return Variable_size_keys_descriptor::size_of_length_field +
+ MY_TEST(field->maybe_null());
+}
+
+
+/*
+ @brief
+ Get the end of the buffer storing the value for the field
+ @param
+ buffer buffer storing the value
+
+ @retval
+ return end of the buffer
+*/
+
+uchar* get_buffer_end(uchar *buffer)
+{
+ return buffer + Variable_size_keys_descriptor::read_packed_length(buffer);
+}
+
+
/*
Histogram_builder is a helper class that is used to build histograms
for columns
@@ -1570,7 +1605,16 @@ public:
return 0;
if (count > bucket_capacity * (curr_bucket + 1))
{
- column->store_field_value((uchar *) elem, col_length);
+ uchar *to= (uchar* )elem;
+ if (column->is_packable())
+ {
+ column->unpack(column->ptr,
+ to + get_offset_to_value(column),
+ get_buffer_end(to), 0);
+ }
+ else
+ column->store_field_value(to, col_length);
+
histogram->set_value(curr_bucket,
column->pos_in_interval(min_value, max_value));
curr_bucket++;
@@ -1621,7 +1665,7 @@ protected:
/* Field for which the number of distinct values is to be find out */
Field *table_field;
- Unique *tree; /* The helper object to contain distinct values */
+ Unique_impl *tree; /* The helper object to contain distinct values */
uint tree_key_length; /* The length of the keys for the elements of 'tree */
ulonglong distincts;
@@ -1646,13 +1690,11 @@ public:
of the parameters to be passed to the constructor of the Unique object.
*/
- Count_distinct_field(Field *field, size_t max_heap_table_size)
+ Count_distinct_field(Field *field)
{
table_field= field;
- tree_key_length= field->pack_length();
-
- tree= new Unique((qsort_cmp2) simple_str_key_cmp, (void*) field,
- tree_key_length, max_heap_table_size, 1);
+ tree_key_length= 0;
+ tree= NULL;
}
virtual ~Count_distinct_field()
@@ -1670,6 +1712,63 @@ public:
return (tree != NULL);
}
+
+ /*
+ @brief
+ Calculate the max length to store the length of a packable field
+
+ @param
+ field Field structure
+
+ @retval
+ Return the max length for a packable field
+ */
+
+ uint compute_packable_length(Field *field)
+ {
+ return table_field->max_packed_col_length(table_field->pack_length()) +
+ Variable_size_keys_descriptor::size_of_length_field +
+ MY_TEST(table_field->maybe_null());
+ }
+
+
+ /*
+ @brief
+ Create and setup the Unique object for the column
+
+ @param
+ thd Thread structure
+ max_heap_table_size max allowed size of the unique tree
+
+ @retval
+ TRUE ERROR
+ FALSE SUCCESS
+ */
+
+ virtual bool setup(THD *thd, size_t max_heap_table_size)
+ {
+ Descriptor *desc;
+ if (table_field->is_packable())
+ {
+ tree_key_length= compute_packable_length(table_field);
+ desc= new Variable_size_keys_simple(tree_key_length);
+ }
+ else
+ {
+ tree_key_length= table_field->pack_length();
+ desc= new Fixed_size_keys_descriptor(tree_key_length);
+ }
+ if (!desc)
+ return true; // OOM
+ tree= new Unique_impl((qsort_cmp2) key_cmp,
+ (void*) this, tree_key_length,
+ max_heap_table_size, 1, desc);
+ if (!tree)
+ return true; // OOM
+ return tree->get_descriptor()->setup_for_field(thd, table_field);
+ }
+
+
/*
@brief
Add the value of 'field' to the container of the Unique object 'tree'
@@ -1677,6 +1776,14 @@ public:
virtual bool add()
{
table_field->mark_unused_memory_as_defined();
+ DBUG_ASSERT(tree);
+ if (tree->is_variable_sized())
+ {
+ Descriptor *descriptor= tree->get_descriptor();
+ uchar *rec_ptr= descriptor->make_record(true);
+ DBUG_ASSERT(descriptor->get_length_of_key(rec_ptr) <= tree->get_size());
+ return tree->unique_add(rec_ptr);
+ }
return tree->unique_add(table_field->ptr);
}
@@ -1733,17 +1840,31 @@ public:
return table_field->collected_stats->histogram.get_values();
}
+ static int key_cmp(void* arg, uchar* key1, uchar* key2);
};
+/*
+ @brief
+ Compare function for packed keys
+ @param arg Pointer to the relevant class instance
+ @param key1 left key image
+ @param key2 right key image
-static
-int simple_ulonglong_key_cmp(void* arg, uchar* key1, uchar* key2)
+
+ @return comparison result
+ @retval < 0 if key1 < key2
+ @retval = 0 if key1 = key2
+ @retval > 0 if key1 > key2
+*/
+int Count_distinct_field::key_cmp(void* arg,
+ uchar* key1,
+ uchar* key2)
{
- ulonglong *val1= (ulonglong *) key1;
- ulonglong *val2= (ulonglong *) key2;
- return *val1 > *val2 ? 1 : *val1 == *val2 ? 0 : -1;
+ Count_distinct_field *compare_arg= (Count_distinct_field*)arg;
+ DBUG_ASSERT(compare_arg->tree->get_descriptor());
+ return compare_arg->tree->get_descriptor()->compare_keys(key1, key2);
}
-
+
/*
The class Count_distinct_field_bit is derived from the class
@@ -1755,24 +1876,52 @@ class Count_distinct_field_bit: public Count_distinct_field
{
public:
- Count_distinct_field_bit(Field *field, size_t max_heap_table_size)
- {
- table_field= field;
- tree_key_length= sizeof(ulonglong);
-
- tree= new Unique((qsort_cmp2) simple_ulonglong_key_cmp,
- (void*) &tree_key_length,
- tree_key_length, max_heap_table_size, 1);
- }
+ Count_distinct_field_bit(Field *field): Count_distinct_field(field){}
bool add()
{
- longlong val= table_field->val_int();
+ longlong val= table_field->val_int();
return tree->unique_add(&val);
}
+ bool setup(THD *thd, size_t max_heap_table_size) override
+ {
+ tree_key_length= sizeof(ulonglong);
+ Descriptor *desc= new Fixed_size_keys_mem_comparable(tree_key_length);
+ if (!desc)
+ return true;
+ tree= new Unique_impl((qsort_cmp2) simple_ulonglong_key_cmp,
+ (void*) this,
+ tree_key_length, max_heap_table_size, 1, desc);
+ return tree == NULL;
+ }
+ static int simple_ulonglong_key_cmp(void* arg, uchar* key1, uchar* key2);
};
+/*
+ @brief
+ Compare function for Bit fields
+
+ @param arg Pointer to the relevant class instance
+ @param key1 left key image
+ @param key2 right key image
+
+
+ @return comparison result
+ @retval < 0 if key1 < key2
+ @retval = 0 if key1 = key2
+ @retval > 0 if key1 > key2
+*/
+int Count_distinct_field_bit::simple_ulonglong_key_cmp(void* arg,
+ uchar* key1,
+ uchar* key2)
+{
+ Count_distinct_field_bit *compare_arg= (Count_distinct_field_bit*)arg;
+ DBUG_ASSERT(compare_arg->tree->get_descriptor());
+ return compare_arg->tree->get_descriptor()->compare_keys(key1, key2);
+}
+
+
/*
The class Index_prefix_calc is a helper class used to calculate the values
for the column 'avg_frequency' of the statistical table index_stats.
@@ -2344,8 +2493,11 @@ void Column_statistics_collected::init(THD *thd, Field *table_field)
{
count_distinct=
table_field->type() == MYSQL_TYPE_BIT ?
- new Count_distinct_field_bit(table_field, max_heap_table_size) :
- new Count_distinct_field(table_field, max_heap_table_size);
+ new Count_distinct_field_bit(table_field) :
+ new Count_distinct_field(table_field);
+
+ if (count_distinct && count_distinct->setup(thd, max_heap_table_size))
+ count_distinct= NULL;
}
if (count_distinct && !count_distinct->exists())
count_distinct= NULL;