1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-9740: Window functions: catch invalid window frame specs

Catch errors in window frame definitions
This commit is contained in:
Sergei Petrunia
2016-03-17 16:52:23 +03:00
parent c3ab9712b0
commit ee9297f656
4 changed files with 175 additions and 0 deletions

View File

@ -76,6 +76,10 @@ Window_frame::check_frame_bounds()
}
/*
Setup window functions in a select
*/
int
setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields,
@ -122,6 +126,80 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
{
DBUG_RETURN(1);
}
/*
For "win_func() OVER (ORDER BY order_list RANGE BETWEEN ...)",
- ORDER BY order_list must not be ommitted
- the list must have a single element.
*/
if (win_spec->window_frame &&
win_spec->window_frame->units == Window_frame::UNITS_RANGE)
{
if (!win_spec->order_list || win_spec->order_list->elements != 1)
{
my_error(ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY, MYF(0));
DBUG_RETURN(1);
}
/*
"The declared type of SK shall be numeric, datetime, or interval"
we don't support datetime or interval, yet.
*/
Item_result rtype= win_spec->order_list->first->item[0]->result_type();
if (rtype != REAL_RESULT && rtype != INT_RESULT &&
rtype != DECIMAL_RESULT)
{
my_error(ER_WRONG_TYPE_FOR_RANGE_FRAME, MYF(0));
DBUG_RETURN(1);
}
/*
"The declared type of UVS shall be numeric if the declared type of SK
is numeric; otherwise, it shall be an interval type that may be added
to or subtracted from the declared type of SK"
*/
Window_frame_bound *bounds[]= {win_spec->window_frame->top_bound,
win_spec->window_frame->bottom_bound,
NULL};
for (Window_frame_bound **pbound= &bounds[0]; *pbound; pbound++)
{
if (!(*pbound)->is_unbounded() &&
((*pbound)->precedence_type == Window_frame_bound::FOLLOWING ||
(*pbound)->precedence_type == Window_frame_bound::PRECEDING))
{
Item_result rtype= (*pbound)->offset->result_type();
if (rtype != REAL_RESULT && rtype != INT_RESULT &&
rtype != DECIMAL_RESULT)
{
my_error(ER_WRONG_TYPE_FOR_RANGE_FRAME, MYF(0));
DBUG_RETURN(1);
}
}
}
}
/* "ROWS PRECEDING|FOLLOWING $n" must have a numeric $n */
if (win_spec->window_frame &&
win_spec->window_frame->units == Window_frame::UNITS_ROWS)
{
Window_frame_bound *bounds[]= {win_spec->window_frame->top_bound,
win_spec->window_frame->bottom_bound,
NULL};
for (Window_frame_bound **pbound= &bounds[0]; *pbound; pbound++)
{
if (!(*pbound)->is_unbounded() &&
((*pbound)->precedence_type == Window_frame_bound::FOLLOWING ||
(*pbound)->precedence_type == Window_frame_bound::PRECEDING))
{
Item *offset= (*pbound)->offset;
if (offset->result_type() != INT_RESULT)
{
my_error(ER_WRONG_TYPE_FOR_ROWS_FRAME, MYF(0));
DBUG_RETURN(1);
}
}
}
}
}
DBUG_RETURN(0);
}
@ -1123,6 +1201,9 @@ Frame_cursor *get_frame_cursor(Window_frame *frame, bool is_top_bound)
if (frame->units == Window_frame::UNITS_ROWS)
{
longlong n_rows= bound->offset->val_int();
/* These should be handled in the parser */
DBUG_ASSERT(!bound->offset->null_value);
DBUG_ASSERT(n_rows > 0);
if (is_preceding)
return new Frame_n_rows_preceding(is_top_bound, n_rows);
else