summaryrefslogtreecommitdiff
path: root/sql/sql_window.cc
diff options
context:
space:
mode:
authorSergei Petrunia <sergey@mariadb.com>2022-05-03 14:06:27 +0300
committerSergei Petrunia <sergey@mariadb.com>2022-05-04 15:47:45 +0300
commitba4927e520190bbad763bb5260ae154f29a61231 (patch)
treeb261a4a612505740e071456b649865eceaf9a252 /sql/sql_window.cc
parent794bebf9ee18de4138c4d2c93853d49ff3af7f12 (diff)
downloadmariadb-git-ba4927e520190bbad763bb5260ae154f29a61231.tar.gz
MDEV-19398: Assertion `item1->type() == Item::FIELD_ITEM ...
Window Functions code tries to minimize the number of times it needs to sort the select's resultset by finding "compatible" OVER (PARTITION BY ... ORDER BY ...) clauses. This employs compare_order_elements(). That function assumed that the order expressions are Item_field-derived objects (that refer to a temp.table). But this is not always the case: one can construct queries order expressions are arbitrary item expressions. Add handling for such expressions: sort them according to the window specification they appeared in. This means we cannot detect that two compatible PARTITION BY clauses that use expressions can share the sorting step. But at least we won't crash.
Diffstat (limited to 'sql/sql_window.cc')
-rw-r--r--sql/sql_window.cc65
1 files changed, 55 insertions, 10 deletions
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 3ef751bc5b9..8afdaa1e6da 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -312,15 +312,49 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
#define CMP_GT 2 // Greater then
static
-int compare_order_elements(ORDER *ord1, ORDER *ord2)
+int compare_order_elements(ORDER *ord1, int weight1,
+ ORDER *ord2, int weight2)
{
if (*ord1->item == *ord2->item && ord1->direction == ord2->direction)
return CMP_EQ;
Item *item1= (*ord1->item)->real_item();
Item *item2= (*ord2->item)->real_item();
- DBUG_ASSERT(item1->type() == Item::FIELD_ITEM &&
- item2->type() == Item::FIELD_ITEM);
- ptrdiff_t cmp= ((Item_field *) item1)->field - ((Item_field *) item2)->field;
+
+ bool item1_field= (item1->type() == Item::FIELD_ITEM);
+ bool item2_field= (item2->type() == Item::FIELD_ITEM);
+
+ ptrdiff_t cmp;
+ if (item1_field && item2_field)
+ {
+ DBUG_ASSERT(((Item_field *) item1)->field->table ==
+ ((Item_field *) item2)->field->table);
+ cmp= ((Item_field *) item1)->field->field_index -
+ ((Item_field *) item2)->field->field_index;
+ }
+ else if (item1_field && !item2_field)
+ return CMP_LT;
+ else if (!item1_field && item2_field)
+ return CMP_LT;
+ else
+ {
+ /*
+ Ok, item1_field==NULL and item2_field==NULL.
+ We're not able to compare Item expressions. Order them according to
+ their passed "weight" (which comes from Window_spec::win_spec_number):
+ */
+ if (weight1 != weight2)
+ cmp= weight1 - weight2;
+ else
+ {
+ /*
+ The weight is the same. That is, the elements come from the same
+ window specification... This shouldn't happen.
+ */
+ DBUG_ASSERT(0);
+ cmp= item1 - item2;
+ }
+ }
+
if (cmp == 0)
{
if (ord1->direction == ord2->direction)
@@ -333,7 +367,9 @@ int compare_order_elements(ORDER *ord1, ORDER *ord2)
static
int compare_order_lists(SQL_I_List<ORDER> *part_list1,
- SQL_I_List<ORDER> *part_list2)
+ int spec_number1,
+ SQL_I_List<ORDER> *part_list2,
+ int spec_number2)
{
if (part_list1 == part_list2)
return CMP_EQ;
@@ -358,7 +394,8 @@ int compare_order_lists(SQL_I_List<ORDER> *part_list1,
if (!elem1 || !elem2)
break;
- if ((cmp= compare_order_elements(elem1, elem2)))
+ if ((cmp= compare_order_elements(elem1, spec_number1,
+ elem2, spec_number2)))
return cmp;
}
if (elem1)
@@ -453,7 +490,9 @@ int compare_window_spec_joined_lists(Window_spec *win_spec1,
win_spec1->join_partition_and_order_lists();
win_spec2->join_partition_and_order_lists();
int cmp= compare_order_lists(win_spec1->partition_list,
- win_spec2->partition_list);
+ win_spec1->win_spec_number,
+ win_spec2->partition_list,
+ win_spec2->win_spec_number);
win_spec1->disjoin_partition_and_order_lists();
win_spec2->disjoin_partition_and_order_lists();
return cmp;
@@ -471,7 +510,9 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
if (win_spec1 == win_spec2)
return CMP_EQ;
cmp= compare_order_lists(win_spec1->partition_list,
- win_spec2->partition_list);
+ win_spec1->win_spec_number,
+ win_spec2->partition_list,
+ win_spec2->win_spec_number);
if (cmp == CMP_EQ)
{
/*
@@ -490,7 +531,9 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
}
cmp= compare_order_lists(win_spec1->order_list,
- win_spec2->order_list);
+ win_spec1->win_spec_number,
+ win_spec2->order_list,
+ win_spec2->win_spec_number);
if (cmp != CMP_EQ)
return cmp;
@@ -587,7 +630,9 @@ void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list)
int cmp;
if (win_spec_prev->partition_list == win_spec_curr->partition_list)
cmp= compare_order_lists(win_spec_prev->order_list,
- win_spec_curr->order_list);
+ win_spec_prev->win_spec_number,
+ win_spec_curr->order_list,
+ win_spec_curr->win_spec_number);
else
cmp= compare_window_spec_joined_lists(win_spec_prev, win_spec_curr);
if (!(CMP_LT_C <= cmp && cmp <= CMP_GT_C))