[mysql][window function]: fix 4 order by bugs in ob-mysql window function.
This commit is contained in:
@ -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)) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user