[mysql][window function]: fix 4 order by bugs in ob-mysql window function.

This commit is contained in:
Monk-Liu
2022-03-28 16:34:46 +08:00
committed by LINxiansheng
parent 5e0b6e4c8c
commit 403f881b89
10 changed files with 461 additions and 289 deletions

View File

@ -4976,8 +4976,10 @@ int ObSelectResolver::resolve_win_func_exprs(ObRawExpr*& expr, common::ObIArray<
LOG_WARN("failed to handle compat with mysql ntile.", K(ret));
} else if (N >= OB_MAX_WINDOW_FUNCTION_NUM) {
ret = OB_ERR_INVALID_WINDOW_FUNC_USE;
LOG_WARN("invalid window func num", K(ret), K(N), K(OB_MAX_WINDOW_FUNCTION_NUM));
} else if (OB_FAIL(check_orderby_type_validity(win_expr))) {
// need to check order by here, since the basic column type is resolve
LOG_WARN("invalid window func orderby type", K(ret), K(*win_expr));
} else if (OB_ISNULL(final_win_expr = select_stmt->get_same_win_func_item(win_expr))) {
ret = select_stmt->add_window_func_expr(win_expr);
} else if (ObRawExprUtils::replace_ref_column(expr, win_exprs.at(i), final_win_expr)) {
@ -5542,7 +5544,49 @@ int ObSelectResolver::identify_anchor_member(
return ret;
}
int ObSelectResolver::check_ntile_compatiable_with_mysql(ObWinFunRawExpr* win_expr)
int ObSelectResolver::check_orderby_type_validity(ObWinFunRawExpr *win_expr)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(win_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("win expr is null.", K(ret));
} else if (win_expr->has_order_items() && win_expr->win_type_ == WINDOW_RANGE &&
(win_expr->get_upper().type_ == BOUND_INTERVAL || win_expr->get_lower().type_ == BOUND_INTERVAL)) {
for (int64_t i = 0; OB_SUCC(ret) && i < win_expr->order_items_.count(); i++) {
const OrderItem order_item = win_expr->order_items_.at(i);
if (OB_ISNULL(order_item.expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("win expr unexpected null order by", K(ret));
} else if (OB_FAIL(order_item.expr_->formalize(session_info_))) {
LOG_WARN("order item can't be formalized", K(ret));
} else {
ObObjType data_type = order_item.expr_->get_data_type();
if (share::is_mysql_mode()) {
if (data_type == 0 || // NULL
ob_is_int_tc(data_type) || ob_is_uint_tc(data_type) || ob_is_float_tc(data_type) ||
ob_is_double_tc(data_type) || ob_is_number_tc(data_type) || ob_is_datetime_tc(data_type) ||
ob_is_date_tc(data_type) || ob_is_otimestampe_tc(data_type) || ob_is_time_tc(data_type) ||
ob_is_year_tc(data_type)) {
// in mysql, only the above types are allowed in window order by.
} else {
ret = OB_ERR_WINDOW_RANGE_FRAME_ORDER_TYPE;
LOG_WARN("RANGE N PRECEDING/FOLLOWING frame order by type miss match", K(ret), K(data_type));
}
} else {
if (ob_is_number_tc(data_type) || ob_is_datetime_tc(data_type)) {
// the above type are allowed in oracle
} else {
ret = OB_ERR_INVALID_WINDOW_FUNC_USE;
LOG_WARN("invalid datatype in order by for range clause", K(ret), K(data_type));
}
}
}
}
}
return ret;
}
int ObSelectResolver::check_ntile_compatiable_with_mysql(ObWinFunRawExpr *win_expr)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(win_expr)) {

View File

@ -406,6 +406,7 @@ private:
int check_duplicated_name_window(ObString& name, const ParseNode* node, int64_t resolved);
int mock_to_named_windows(ObString& name, ParseNode* win_node);
int can_find_group_column(ObRawExpr* col_expr, const common::ObIArray<ObRawExpr*>& exprs, bool& can_find);
int check_orderby_type_validity(ObWinFunRawExpr *win_expr);
int can_find_group_column(
ObRawExpr* col_expr, const common::ObIArray<ObGroupingSetsItem>& grouping_sets_items, bool& can_find);
int can_find_group_column(ObRawExpr* col_expr, const ObIArray<ObMultiRollupItem>& multi_rollup_items, bool& can_find);

View File

@ -3876,7 +3876,17 @@ int ObRawExprResolverImpl::not_row_check(const ObRawExpr* expr)
return ret;
}
int ObRawExprResolverImpl::param_not_row_check(const ObRawExpr* expr)
int ObRawExprResolverImpl::not_int_check(const ObRawExpr *expr)
{
int ret = OB_SUCCESS;
if (share::is_mysql_mode() && NULL != expr && T_INT == expr->get_expr_type()) {
ret = OB_ERR_WINDOW_ILLEGAL_ORDER_BY;
LOG_WARN("int not expected in window function's orderby ", K(ret));
}
return ret;
}
int ObRawExprResolverImpl::param_not_row_check(const ObRawExpr *expr)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && NULL != expr && i < expr->get_param_count(); i++) {
@ -4299,6 +4309,10 @@ int ObRawExprResolverImpl::process_sort_list_node(const ParseNode* node, ObIArra
LOG_WARN("fail to recursive resolve order item expr", K(ret));
} else {
OZ(not_row_check(order_item.expr_));
// check order_item.expr_:
// 1. shouldn't be int,
// 2. if is number, ignore the order_item.(all group are in same group);
OZ(not_int_check(order_item.expr_));
OZ(order_items.push_back(order_item));
}
}
@ -4343,6 +4357,21 @@ int ObRawExprResolverImpl::process_frame_node(const ParseNode* node, ObFrame& fr
LOG_WARN("process lower bound node failed", K(ret));
}
}
/* check the frame
* In mysql, ROWS can't coexists with (INTERVAL expr unit).
* mysql: select c1, sum(c1) over(order by c1 rows interval 5 day preceding) from t1;
* mysql will raise error: ERROR 3596 (HY000): INTERVAL can only be used with RANGE frames.
*/
if (OB_SUCC(ret) && share::is_mysql_mode() && frame.win_type_ == WINDOW_ROWS) {
if (frame.get_upper().type_ == BOUND_INTERVAL && !frame.get_upper().is_nmb_literal_) {
// upper is a (INTERVAL expr unit)
ret = OB_ERR_WINDOW_ROWS_INTERVAL_USE;
LOG_WARN("INTERVAL can only be used with RANGE frames.", K(ret));
} else if (frame.get_lower().type_ == BOUND_INTERVAL && !frame.get_lower().is_nmb_literal_) {
ret = OB_ERR_WINDOW_ROWS_INTERVAL_USE;
LOG_WARN("INTERVAL can only be used with RANGE frames.", K(ret));
}
}
}
}
@ -4524,9 +4553,16 @@ int ObRawExprResolverImpl::check_and_canonicalize_window_expr(ObRawExpr* expr)
}
}
if (OB_SUCC(ret) && share::is_mysql_mode() && w_expr->has_frame_orig() &&
WINDOW_RANGE == win_type && 0 == order_items.count()) {
ret = OB_ERR_MISS_ORDER_BY_EXPR;
if (OB_SUCC(ret) && share::is_mysql_mode() && w_expr->has_frame_orig() && WINDOW_RANGE == win_type &&
0 == order_items.count() &&
(w_expr->get_upper().type_ == BOUND_INTERVAL || w_expr->get_lower().type_ == BOUND_INTERVAL)) {
/* if preceding or following has a specific value (not the default unbounded)
* in mysql:
* @OK: select c1, sum(c1) over(range between current row and current row) from t1;
* @OK: select c1, sum(c1) over(range unbounded preceding) from t1;
* @error: select c1, sum(c1) over(range 1 preceding) from t1; --error 3587
*/
ret = OB_ERR_WINDOW_RANGE_FRAME_ORDER_TYPE;
LOG_WARN("missing ORDER BY expression in the window specification", K(ret));
}

View File

@ -142,6 +142,7 @@ private:
static int not_row_check(const ObRawExpr* expr);
static int param_not_row_check(const ObRawExpr* expr);
int cast_accuracy_check(const ParseNode *node, const char *input);
static int not_int_check(const ObRawExpr *expr);
private:
int transform_ratio_afun_to_arg_div_sum(const ParseNode* ratio_to_report, ParseNode*& div);