mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-9740: Window functions: catch invalid window frame specs
Catch errors in window frame definitions
This commit is contained in:
@ -1177,6 +1177,44 @@ pk c cnt
|
|||||||
9 2 0
|
9 2 0
|
||||||
10 2 0
|
10 2 0
|
||||||
drop table t0, t1;
|
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
|
# Window function in grouping query
|
||||||
#
|
#
|
||||||
|
@ -697,6 +697,51 @@ select
|
|||||||
from t1;
|
from t1;
|
||||||
drop table t0, 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 #
|
||||||
--echo # Window function in grouping query
|
--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"
|
eng "Referenced window specification '%s' cannot contain window frame"
|
||||||
ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS
|
ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS
|
||||||
eng "Unacceptable combination of window frame bound specifications"
|
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
|
int
|
||||||
setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
|
setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
|
||||||
List<Item> &fields, List<Item> &all_fields,
|
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);
|
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);
|
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)
|
if (frame->units == Window_frame::UNITS_ROWS)
|
||||||
{
|
{
|
||||||
longlong n_rows= bound->offset->val_int();
|
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)
|
if (is_preceding)
|
||||||
return new Frame_n_rows_preceding(is_top_bound, n_rows);
|
return new Frame_n_rows_preceding(is_top_bound, n_rows);
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user