Commit ee9297f6 authored by Sergei Petrunia's avatar Sergei Petrunia

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

Catch errors in window frame definitions
parent c3ab9712
......@@ -1177,6 +1177,44 @@ pk c cnt
9 2 0
10 2 0
drop table t0, t1;
#
# Error checking for frame bounds
#
create table t1 (a int, b int, c varchar(32));
insert into t1 values (1,1,'foo');
insert into t1 values (2,2,'bar');
select
count(*) over (order by a,b
range between unbounded preceding and current row)
from t1;
ERROR HY000: RANGE-type frame requires ORDER BY clause with single sort key
select
count(*) over (order by c
range between unbounded preceding and current row)
from t1;
ERROR HY000: Numeric datatype is required for RANGE-type frame
select
count(*) over (order by a
range between 'abcd' preceding and current row)
from t1;
ERROR HY000: Numeric datatype is required for RANGE-type frame
select
count(*) over (order by a
range between current row and 'foo' following)
from t1;
ERROR HY000: Numeric datatype is required for RANGE-type frame
# Try range frame with invalid bounds
select
count(*) over (order by a
rows between 0.5 preceding and current row)
from t1;
ERROR HY000: Integer is required for ROWS-type frame
select
count(*) over (order by a
rows between current row and 3.14 following)
from t1;
ERROR HY000: Integer is required for ROWS-type frame
drop table t1;
#
# Window function in grouping query
#
......
......@@ -697,6 +697,51 @@ select
from t1;
drop table t0, t1;
--echo #
--echo # Error checking for frame bounds
--echo #
create table t1 (a int, b int, c varchar(32));
insert into t1 values (1,1,'foo');
insert into t1 values (2,2,'bar');
--error ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY
select
count(*) over (order by a,b
range between unbounded preceding and current row)
from t1;
--error ER_WRONG_TYPE_FOR_RANGE_FRAME
select
count(*) over (order by c
range between unbounded preceding and current row)
from t1;
--error ER_WRONG_TYPE_FOR_RANGE_FRAME
select
count(*) over (order by a
range between 'abcd' preceding and current row)
from t1;
--error ER_WRONG_TYPE_FOR_RANGE_FRAME
select
count(*) over (order by a
range between current row and 'foo' following)
from t1;
--echo # Try range frame with invalid bounds
--error ER_WRONG_TYPE_FOR_ROWS_FRAME
select
count(*) over (order by a
rows between 0.5 preceding and current row)
from t1;
--error ER_WRONG_TYPE_FOR_ROWS_FRAME
select
count(*) over (order by a
rows between current row and 3.14 following)
from t1;
drop table t1;
--echo #
--echo # Window function in grouping query
......@@ -742,3 +787,8 @@ drop table t1;
......@@ -7148,4 +7148,10 @@ ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC
eng "Referenced window specification '%s' cannot contain window frame"
ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS
eng "Unacceptable combination of window frame bound specifications"
ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY
eng "RANGE-type frame requires ORDER BY clause with single sort key"
ER_WRONG_TYPE_FOR_ROWS_FRAME
eng "Integer is required for ROWS-type frame"
ER_WRONG_TYPE_FOR_RANGE_FRAME
eng "Numeric datatype is required for RANGE-type frame"
......@@ -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
......
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