Commit 9a83ddda authored by evgen@moonbone.local's avatar evgen@moonbone.local

Bug#30245: A wrong type of a BIT field is reported when grouped by it.

HEAP tables can't index BIT fields. Due to this when grouping by such fields is
needed they are converted to a fields of the LONG type when temporary table
is being created. But a side effect of this is that a wrong type of BIT
fields is returned to a client.

Now the JOIN::prepare and the create_distinct_group functions are create
additional hidden copy of BIT fields to preserve original fields untouched.
New hidden fields are used for grouping instead.
parent 1cc8f0e3
...@@ -642,4 +642,19 @@ b+0 COUNT(DISTINCT a) ...@@ -642,4 +642,19 @@ b+0 COUNT(DISTINCT a)
1 1 1 1
3 2 3 2
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (b BIT);
INSERT INTO t1 (b) VALUES (1), (0);
SELECT DISTINCT b FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t1 t1 b b 16 1 1 Y 32 0 63
b
#
#
SELECT b FROM t1 GROUP BY b;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t1 t1 b b 16 1 1 Y 32 0 63
b
#
#
DROP TABLE t1;
End of 5.0 tests End of 5.0 tests
...@@ -291,4 +291,17 @@ INSERT INTO t1 (b, a) VALUES (1, 1), (3, 2), (0, 3), (3, 4); ...@@ -291,4 +291,17 @@ INSERT INTO t1 (b, a) VALUES (1, 1), (3, 2), (0, 3), (3, 4);
SELECT b+0, COUNT(DISTINCT a) FROM t1 GROUP BY b; SELECT b+0, COUNT(DISTINCT a) FROM t1 GROUP BY b;
DROP TABLE t1; DROP TABLE t1;
#
# Bug#30245: A wrong type of a BIT field is reported when grouped by it.
#
CREATE TABLE t1 (b BIT);
INSERT INTO t1 (b) VALUES (1), (0);
--enable_metadata
--replace_column 1 #
SELECT DISTINCT b FROM t1;
--replace_column 1 #
SELECT b FROM t1 GROUP BY b;
--disable_metadata
DROP TABLE t1;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -189,6 +189,7 @@ static bool setup_new_fields(THD *thd, List<Item> &fields, ...@@ -189,6 +189,7 @@ static bool setup_new_fields(THD *thd, List<Item> &fields,
List<Item> &all_fields, ORDER *new_order); List<Item> &all_fields, ORDER *new_order);
static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array, static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array,
ORDER *order, List<Item> &fields, ORDER *order, List<Item> &fields,
List<Item> &all_fields,
bool *all_order_by_fields_used); bool *all_order_by_fields_used);
static bool test_if_subpart(ORDER *a,ORDER *b); static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
...@@ -537,6 +538,28 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -537,6 +538,28 @@ JOIN::prepare(Item ***rref_pointer_array,
fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array)) fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (group)
{
/*
Because HEAP tables can't index BIT fields we need to use an
additional hidden field for grouping because later it will be
converted to a LONG field. Original field will remain of the
BIT type and will be returned to a client.
*/
for (ORDER *ord= group_list; ord; ord= ord->next)
{
if ((*ord->item)->type() == Item::FIELD_ITEM &&
(*ord->item)->field_type() == MYSQL_TYPE_BIT)
{
Item_field *field= new Item_field(thd, *(Item_field**)ord->item);
int el= all_fields.elements;
ref_pointer_array[el]= field;
all_fields.push_front(field);
ord->item= ref_pointer_array + el;
}
}
}
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -1068,12 +1091,13 @@ JOIN::optimize() ...@@ -1068,12 +1091,13 @@ JOIN::optimize()
if (order) if (order)
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
order, fields_list, order, fields_list, all_fields,
&all_order_fields_used))) &all_order_fields_used)))
{ {
bool skip_group= (skip_sort_order && bool skip_group= (skip_sort_order &&
test_if_skip_sort_order(tab, group_list, select_limit, test_if_skip_sort_order(tab, group_list, select_limit,
1) != 0); 1) != 0);
count_field_types(select_lex, &tmp_table_param, all_fields, 0);
if ((skip_group && all_order_fields_used) || if ((skip_group && all_order_fields_used) ||
select_limit == HA_POS_ERROR || select_limit == HA_POS_ERROR ||
(order && !skip_sort_order)) (order && !skip_sort_order))
...@@ -13647,10 +13671,11 @@ setup_new_fields(THD *thd, List<Item> &fields, ...@@ -13647,10 +13671,11 @@ setup_new_fields(THD *thd, List<Item> &fields,
static ORDER * static ORDER *
create_distinct_group(THD *thd, Item **ref_pointer_array, create_distinct_group(THD *thd, Item **ref_pointer_array,
ORDER *order_list, List<Item> &fields, ORDER *order_list, List<Item> &fields,
List<Item> &all_fields,
bool *all_order_by_fields_used) bool *all_order_by_fields_used)
{ {
List_iterator<Item> li(fields); List_iterator<Item> li(fields);
Item *item; Item *item, **orig_ref_pointer_array= ref_pointer_array;
ORDER *order,*group,**prev; ORDER *order,*group,**prev;
*all_order_by_fields_used= 1; *all_order_by_fields_used= 1;
...@@ -13690,12 +13715,31 @@ create_distinct_group(THD *thd, Item **ref_pointer_array, ...@@ -13690,12 +13715,31 @@ create_distinct_group(THD *thd, Item **ref_pointer_array,
ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
if (!ord) if (!ord)
return 0; return 0;
if (item->type() == Item::FIELD_ITEM &&
item->field_type() == MYSQL_TYPE_BIT)
{
/*
Because HEAP tables can't index BIT fields we need to use an
additional hidden field for grouping because later it will be
converted to a LONG field. Original field will remain of the
BIT type and will be returned to a client.
*/
Item_field *new_item= new Item_field(thd, (Item_field*)item);
int el= all_fields.elements;
orig_ref_pointer_array[el]= new_item;
all_fields.push_front(new_item);
ord->item= orig_ref_pointer_array + el;
}
else
{
/* /*
We have here only field_list (not all_field_list), so we can use We have here only field_list (not all_field_list), so we can use
simple indexing of ref_pointer_array (order in the array and in the simple indexing of ref_pointer_array (order in the array and in the
list are same) list are same)
*/ */
ord->item= ref_pointer_array; ord->item= ref_pointer_array;
}
ord->asc=1; ord->asc=1;
*prev=ord; *prev=ord;
prev= &ord->next; prev= &ord->next;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment