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:
@ -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
|
||||
|
Reference in New Issue
Block a user