Commit 5ff4b21e authored by Igor Babaev's avatar Igor Babaev

Fixed bug mdev-9897.

This bug revealed a serious problem: if the same partition list
was used in two window specifications then the temporary table created
to calculate window functions contained fields for two identical
partitions. This problem was fixed as well.
parent b532be9f
......@@ -1916,3 +1916,27 @@ EXPLAIN
}
}
drop table t1;
#
# MDEV-9893: Window functions with different ORDER BY lists,
# one of these lists containing an expression
#
create table t1 (s1 int, s2 char(5));
insert into t1 values (1,'a');
insert into t1 values (null,null);
insert into t1 values (1,null);
insert into t1 values (null,'a');
insert into t1 values (2,'b');
insert into t1 values (-1,'');
select
*,
ROW_NUMBER() OVER (order by s1),
CUME_DIST() OVER (order by -s1)
from t1;
s1 s2 ROW_NUMBER() OVER (order by s1) CUME_DIST() OVER (order by -s1)
1 a 4 0.8333333333
NULL NULL 1 0.3333333333
1 NULL 5 0.8333333333
NULL a 2 0.3333333333
2 b 6 0.5000000000
-1 3 1.0000000000
drop table t1;
......@@ -1163,3 +1163,23 @@ select distinct rank() over (partition by part_id order by a) from t1;
drop table t1;
--echo #
--echo # MDEV-9893: Window functions with different ORDER BY lists,
--echo # one of these lists containing an expression
--echo #
create table t1 (s1 int, s2 char(5));
insert into t1 values (1,'a');
insert into t1 values (null,null);
insert into t1 values (1,null);
insert into t1 values (null,'a');
insert into t1 values (2,'b');
insert into t1 values (-1,'');
select
*,
ROW_NUMBER() OVER (order by s1),
CUME_DIST() OVER (order by -s1)
from t1;
drop table t1;
......@@ -6824,6 +6824,8 @@ find_field_in_tables(THD *thd, Item_ident *item,
or as a field name without alias,
or as a field hidden by alias,
or ignoring alias)
limit How many items in the list to check
(if limit==0 then all items are to be checked)
RETURN VALUES
0 Item is not found or item is not unique,
......@@ -6841,9 +6843,10 @@ Item **not_found_item= (Item**) 0x1;
Item **
find_item_in_list(Item *find, List<Item> &items, uint *counter,
find_item_error_report_type report_error,
enum_resolution_type *resolution)
enum_resolution_type *resolution, uint limit)
{
List_iterator<Item> li(items);
uint n_items= limit == 0 ? items.elements : limit;
Item **found=0, **found_unaliased= 0, *item;
const char *db_name=0;
const char *field_name=0;
......@@ -6867,8 +6870,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
db_name= ((Item_ident*) find)->db_name;
}
for (uint i= 0; (item=li++); i++)
for (uint i= 0; i < n_items; i++)
{
item= li++;
if (field_name &&
(item->real_item()->type() == Item::FIELD_ITEM ||
((item->type() == Item::REF_ITEM) &&
......
......@@ -197,7 +197,7 @@ Field *
find_field_in_table_sef(TABLE *table, const char *name);
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error,
enum_resolution_type *resolution);
enum_resolution_type *resolution, uint limit= 0);
bool setup_tables(THD *thd, Name_resolution_context *context,
List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
List<TABLE_LIST> &leaves, bool select_insert,
......
......@@ -21734,6 +21734,7 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
@param[in,out] all_fields All select, group and order by fields
@param[in] is_group_field True if order is a GROUP field, false if
ORDER by field
@param[in] search_in_all_fields If true then search in all_fields
@retval
FALSE if OK
......@@ -21744,7 +21745,7 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
static bool
find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
ORDER *order, List<Item> &fields, List<Item> &all_fields,
bool is_group_field)
bool is_group_field, bool search_in_all_fields)
{
Item *order_item= *order->item; /* The item from the GROUP/ORDER caluse. */
Item::Type order_item_type;
......@@ -21849,6 +21850,18 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables
thd->where);
}
}
else if (search_in_all_fields)
{
Item **found_item= find_item_in_list(order_item, all_fields, &counter,
REPORT_EXCEPT_NOT_FOUND, &resolution,
all_fields.elements - fields.elements);
if (found_item != not_found_item)
{
order->item= &ref_pointer_array[all_fields.elements-1-counter];
order->in_field_list= 0;
return FALSE;
}
}
order->in_field_list=0;
/*
......@@ -21896,14 +21909,15 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables
*/
int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order)
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool search_in_all_fields)
{
enum_parsing_place parsing_place= thd->lex->current_select->parsing_place;
thd->where="order clause";
for (; order; order=order->next)
{
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
all_fields, FALSE))
all_fields, FALSE, search_in_all_fields))
return 1;
if ((*order->item)->with_window_func && parsing_place != IN_ORDER_BY)
{
......@@ -21918,18 +21932,19 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
/**
Intitialize the GROUP BY list.
@param thd Thread handler
@param ref_pointer_array We store references to all fields that was
@param thd Thread handler
@param ref_pointer_array We store references to all fields that was
not in 'fields' here.
@param fields All fields in the select part. Any item in
@param fields All fields in the select part. Any item in
'order' that is part of these list is replaced
by a pointer to this fields.
@param all_fields Total list of all unique fields used by the
@param all_fields Total list of all unique fields used by the
select. All items in 'order' that was not part
of fields will be added first to this list.
@param order The fields we should do GROUP BY on.
@param hidden_group_fields Pointer to flag that is set to 1 if we added
@param order The fields we should do GROUP/PARTITION BY on
@param hidden_group_fields Pointer to flag that is set to 1 if we added
any fields to all_fields.
@param search_in_all_fields If true then search in all_fields
@todo
change ER_WRONG_FIELD_WITH_GROUP to more detailed
......@@ -21944,7 +21959,7 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
int
setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields)
bool *hidden_group_fields, bool search_in_all_fields)
{
enum_parsing_place parsing_place= thd->lex->current_select->parsing_place;
*hidden_group_fields=0;
......@@ -21959,7 +21974,7 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
for (ord= order; ord; ord= ord->next)
{
if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields,
all_fields, TRUE))
all_fields, TRUE, search_in_all_fields))
return 1;
(*ord->item)->marker= UNDEF_POS; /* Mark found */
if ((*ord->item)->with_sum_func && parsing_place == IN_GROUP_BY)
......
......@@ -1942,10 +1942,11 @@ int get_quick_record(SQL_SELECT *select);
SORT_FIELD * make_unireg_sortorder(THD *thd, ORDER *order, uint *length,
SORT_FIELD *sortorder);
int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List <Item> &all_fields, ORDER *order);
List<Item> &fields, List <Item> &all_fields, ORDER *order,
bool search_in_all_fields= true);
int setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
bool *hidden_group_fields, bool search_in_all_fields= true);
bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
Ref_ptr_array ref_pointer_array);
int join_read_key2(THD *thd, struct st_join_table *tab, TABLE *table,
......
......@@ -122,9 +122,10 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
bool hidden_group_fields;
if (win_spec->check_window_names(itp) ||
setup_group(thd, ref_pointer_array, tables, fields, all_fields,
win_spec->partition_list->first, &hidden_group_fields) ||
win_spec->partition_list->first, &hidden_group_fields,
true) ||
setup_order(thd, ref_pointer_array, tables, fields, all_fields,
win_spec->order_list->first) ||
win_spec->order_list->first, true) ||
(win_spec->window_frame &&
win_spec->window_frame->check_frame_bounds()))
{
......@@ -236,21 +237,21 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
static
int compare_order_elements(ORDER *ord1, ORDER *ord2)
{
if (*ord1->item == *ord2->item)
return CMP_EQ;
Item *item1= (*ord1->item)->real_item();
Item *item2= (*ord2->item)->real_item();
if (item1->used_tables() == item2->used_tables())
DBUG_ASSERT(item1->type() == Item::FIELD_ITEM &&
item2->type() == Item::FIELD_ITEM);
int cmp= ((Item_field *) item1)->field - ((Item_field *) item2)->field;
if (cmp == 0)
{
int cmp= strcmp(item1->name, item2->name);
if (cmp == 0)
{
if (ord1->direction == ord2->direction)
return CMP_EQ;
return ord1->direction > ord2->direction ? CMP_GT : CMP_LT;
}
else
return cmp > 0 ? CMP_GT : CMP_LT;
if (ord1->direction == ord2->direction)
return CMP_EQ;
return ord1->direction > ord2->direction ? CMP_GT : CMP_LT;
}
return item1->used_tables() > item2->used_tables() ? CMP_GT : CMP_LT;
else
return cmp > 0 ? CMP_GT : CMP_LT;
}
static
......
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