From a2b5b77779039e15766f0ee95518160b2c62c2b2 Mon Sep 17 00:00:00 2001 From: al0 Date: Mon, 29 Nov 2021 11:30:40 +0800 Subject: [PATCH] implement of any value expr in mysql mode --- deps/oblib/src/lib/ob_name_def.h | 1 + src/sql/CMakeLists.txt | 4 + src/sql/engine/expr/ob_expr_any_value.cpp | 67 +++++++ src/sql/engine/expr/ob_expr_any_value.h | 44 +++++ .../engine/expr/ob_expr_eval_functions.cpp | 3 +- .../engine/expr/ob_expr_operator_factory.cpp | 2 + src/sql/parser/ob_item_type.h | 1 + src/sql/parser/type_name.c | 1 + src/sql/resolver/dml/ob_any_value_checker.cpp | 175 ++++++++++++++++++ src/sql/resolver/dml/ob_any_value_checker.h | 70 +++++++ .../dml/ob_standard_group_checker.cpp | 49 +++-- 11 files changed, 404 insertions(+), 13 deletions(-) create mode 100644 src/sql/engine/expr/ob_expr_any_value.cpp create mode 100644 src/sql/engine/expr/ob_expr_any_value.h create mode 100644 src/sql/resolver/dml/ob_any_value_checker.cpp create mode 100644 src/sql/resolver/dml/ob_any_value_checker.h diff --git a/deps/oblib/src/lib/ob_name_def.h b/deps/oblib/src/lib/ob_name_def.h index 67964ce0cf..7d0df2e7b7 100644 --- a/deps/oblib/src/lib/ob_name_def.h +++ b/deps/oblib/src/lib/ob_name_def.h @@ -335,6 +335,7 @@ #define N_INDEX_FILTER_EXPRS "index_filter_exprs" #define N_OPERATOR_MONITOR_INFO "op_info" #define N_PLAN_MONITOR_INFO "plan_info" +#define N_ANY_VAL "any_value" // common comparison operator #define N_LESS_THAN "<" #define N_GREATER_THAN ">" diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index 216e045bc4..7207441254 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -164,6 +164,8 @@ ob_set_subtarget(ob_sql engine engine/expr/ob_expr.cpp engine/expr/ob_expr_frame_info.cpp engine/expr/ob_expr_user_can_access_obj.cpp + engine/expr/ob_expr_any_value.h + engine/expr/ob_expr_any_value.cpp engine/pdml/ob_batch_row_cache.cpp engine/pdml/ob_pdml_data_driver.cpp engine/pdml/ob_px_multi_part_modify.cpp @@ -950,6 +952,8 @@ ob_set_subtarget(ob_sql resolver resolver/dml/ob_update_stmt.cpp resolver/dml/ob_view_table_resolver.cpp resolver/dml/ob_multi_table_insert_resolver.cpp + resolver/dml/ob_any_value_checker.h + resolver/dml/ob_any_value_checker.cpp resolver/expr/ob_expr_relation_analyzer.cpp resolver/expr/ob_raw_expr.cpp resolver/expr/ob_expr.cpp diff --git a/src/sql/engine/expr/ob_expr_any_value.cpp b/src/sql/engine/expr/ob_expr_any_value.cpp new file mode 100644 index 0000000000..0adad5224c --- /dev/null +++ b/src/sql/engine/expr/ob_expr_any_value.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2014-2021 Alibaba Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * ob_expr_any_value.cpp is for any_value function + * + * Date: 2021/7/9 + * + * Authors: + * ailing.lcq + * + */ + +#include "sql/engine/expr/ob_expr_any_value.h" + +using namespace oceanbase::common; + +namespace oceanbase { +namespace sql { + +ObExprAnyValue::ObExprAnyValue(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ANY_VALUE, N_ANY_VAL, 1, NOT_ROW_DIMENSION) +{} + +ObExprAnyValue::~ObExprAnyValue() +{} + +int ObExprAnyValue::calc_result_type1(ObExprResType &type, ObExprResType &arg, common::ObExprTypeCtx &) const +{ + int ret = OB_SUCCESS; + type = arg; + return ret; +} + +int ObExprAnyValue::calc_result1(common::ObObj &result, const common::ObObj &arg, common::ObExprCtx &expr_ctx) const +{ + UNUSED(expr_ctx); + int ret = OB_SUCCESS; + result = arg; + return ret; +} + +int ObExprAnyValue::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(raw_expr); + UNUSED(expr_cg_ctx); + rt_expr.eval_func_ = ObExprAnyValue::eval_any_value; + return OB_SUCCESS; +} + +int ObExprAnyValue::eval_any_value(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum) +{ + int ret = OB_SUCCESS; + ObDatum *arg = NULL; + if (OB_FAIL(expr.eval_param_value(ctx, arg))) { + SERVER_LOG(WARN, "expr evaluate parameter failed", K(ret)); + } else { + expr_datum.set_datum(*arg); + } + return ret; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_any_value.h b/src/sql/engine/expr/ob_expr_any_value.h new file mode 100644 index 0000000000..f1979eacad --- /dev/null +++ b/src/sql/engine/expr/ob_expr_any_value.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014-2021 Alibaba Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * ob_expr_any_value.h is for any_value function + * + * Date: 2021/7/9 + * + * Authors: + * ailing.lcq + * + */ +#ifndef _OB_EXPR_ANY_VALUE_H_ +#define _OB_EXPR_ANY_VALUE_H_ + +#include "sql/engine/expr/ob_expr_operator.h" + +namespace oceanbase { +namespace sql { +class ObExprAnyValue : public ObFuncExprOperator { +public: + explicit ObExprAnyValue(common::ObIAllocator &alloc); + virtual ~ObExprAnyValue(); + + virtual int calc_result_type1( + ObExprResType &type, ObExprResType &arg, common::ObExprTypeCtx &type_ctx) const override; + + virtual int calc_result1(common::ObObj &result, const common::ObObj &arg, common::ObExprCtx &expr_ctx) const override; + + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + + static int eval_any_value(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum); + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprAnyValue) const; +}; +} // namespace sql +} // namespace oceanbase +#endif /* _OB_EXPR_ANY_VALUE_H_ */ + +// select any_value(); \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_eval_functions.cpp b/src/sql/engine/expr/ob_expr_eval_functions.cpp index de5e207af6..4b94112059 100644 --- a/src/sql/engine/expr/ob_expr_eval_functions.cpp +++ b/src/sql/engine/expr/ob_expr_eval_functions.cpp @@ -186,6 +186,7 @@ #include "ob_expr_convert_tz.h" #include "ob_expr_degrees.h" #include "ob_expr_weight_string.h" +#include "ob_expr_any_value.h" namespace oceanbase { using namespace common; @@ -671,7 +672,7 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { ObExprPeriodAdd::calc_periodadd, /* 409 */ NULL, /* 410 */ NULL, /* 411 */ - NULL, /* 412 */ + ObExprAnyValue::eval_any_value, /* 412 */ NULL, /* 413 */ ObExprDegrees::calc_degrees_expr, /* 414 */ NULL, /* 415 */ diff --git a/src/sql/engine/expr/ob_expr_operator_factory.cpp b/src/sql/engine/expr/ob_expr_operator_factory.cpp index 145fadc9d6..309c68361d 100644 --- a/src/sql/engine/expr/ob_expr_operator_factory.cpp +++ b/src/sql/engine/expr/ob_expr_operator_factory.cpp @@ -270,6 +270,7 @@ #include "sql/engine/expr/ob_expr_convert_tz.h" #include "sql/engine/expr/ob_expr_degrees.h" #include "sql/engine/expr/ob_expr_weight_string.h" +#include "sql/engine/expr/ob_expr_any_value.h" using namespace oceanbase::common; namespace oceanbase { @@ -610,6 +611,7 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP(ObExprTruncate); REG_OP(ObExprDllUdf); REG_OP(ObExprExp); + REG_OP(ObExprAnyValue); /* subquery comparison experator */ REG_OP(ObExprSubQueryRef); REG_OP(ObExprSubQueryEqual); diff --git a/src/sql/parser/ob_item_type.h b/src/sql/parser/ob_item_type.h index a07d2c26a3..4331c4e784 100644 --- a/src/sql/parser/ob_item_type.h +++ b/src/sql/parser/ob_item_type.h @@ -426,6 +426,7 @@ typedef enum ObItemType { T_FUN_SYS_QUARTER = 711, T_FUN_SYS_BIT_LENGTH = 712, T_FUN_SYS_PI = 713, + T_FUN_SYS_ANY_VALUE = 714, T_FUN_SYS_DEGREES = 715, T_FUN_SYS_EXPORT_SET = 721, diff --git a/src/sql/parser/type_name.c b/src/sql/parser/type_name.c index babf80df50..2fab35d3dd 100644 --- a/src/sql/parser/type_name.c +++ b/src/sql/parser/type_name.c @@ -371,6 +371,7 @@ const char* get_type_name(int type) case T_FUN_SYS_QUARTER : return "T_FUN_SYS_QUARTER"; case T_FUN_SYS_BIT_LENGTH : return "T_FUN_SYS_BIT_LENGTH"; case T_FUN_SYS_PI : return "T_FUN_SYS_PI"; + case T_FUN_SYS_ANY_VALUE : return "T_FUN_SYS_ANY_VALUE"; case T_FUN_SYS_DEGREES : return "T_FUN_SYS_DEGREES"; case T_FUN_SYS_EXPORT_SET : return "T_FUN_SYS_EXPORT_SET"; case T_FUN_SYS_INET6NTOA : return "T_FUN_SYS_INET6NTOA"; diff --git a/src/sql/resolver/dml/ob_any_value_checker.cpp b/src/sql/resolver/dml/ob_any_value_checker.cpp new file mode 100644 index 0000000000..8c588f5a79 --- /dev/null +++ b/src/sql/resolver/dml/ob_any_value_checker.cpp @@ -0,0 +1,175 @@ +/** + * Copyright 2014-2021 Alibaba Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * + * Date: 2021/07/14 + * + * ob_any_value_checker.h is for checking any_value expr in mysql's only_full_group_by mode compatible + * + * Authors: + * ailing.lcq + */ +#define USING_LOG_PREFIX SQL_RESV +#include "sql/resolver/dml/ob_any_value_checker.h" +#include "sql/rewrite/ob_transform_utils.h" +#include "lib/oblog/ob_log_module.h" +//#include "lib/utility/ob_macro_utils.h" +namespace oceanbase { +namespace sql { + +int ObAnyValueChecker::visit(ObSysFunRawExpr &expr) +{ + if (T_FUN_SYS_ANY_VALUE == expr.get_expr_type()) { + set_skip_expr(&expr); + } + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObColumnRefRawExpr &expr) +{ + if (undefined_column_ == &expr) { + is_pass_ = false; + } + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObConstRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObVarRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObQueryRefRawExpr &expr) +{ + int ret = OB_SUCCESS; + const ObSelectStmt *ref_stmt = expr.get_ref_stmt(); + if (OB_FAIL(check_select_stmt(ref_stmt))) { + LOG_WARN("failed to check select stmt", K(ret)); + } + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObOpRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObCaseOpRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObAggFunRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObSetOpRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObAliasRefRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObFunMatchAgainst &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObWinFunRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::visit(ObPseudoColumnRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + +int ObAnyValueChecker::check_select_stmt(const ObSelectStmt *ref_stmt) +{ + int ret = OB_SUCCESS; + bool ref_query = false; + LOG_DEBUG("check any value start stmt", K(ret)); + + if (OB_ISNULL(ref_stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ref_stmt should not be NULL", K(ret)); + } else if (OB_FAIL( + ObTransformUtils::is_ref_outer_block_relation(ref_stmt, ref_stmt->get_current_level(), ref_query))) { + LOG_WARN("failed to get ref stmt", K(ret)); + } else if (!ref_query) { + // non ref query + } else { + int32_t ignore_scope = 0; + if (ref_stmt->is_order_siblings()) { + ignore_scope |= RelExprCheckerBase::ORDER_SCOPE; + } + ObArray relation_expr_pointers; + if (OB_FAIL(ref_stmt->get_relation_exprs(relation_expr_pointers, ignore_scope))) { + LOG_WARN("get stmt relation exprs fail", K(ret)); + } + + for (int64_t i = 0; OB_SUCC(ret) && i < relation_expr_pointers.count(); ++i) { + ObRawExpr *expr = relation_expr_pointers.at(i); + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr in relation_expr_pointers is null", K(i), K(relation_expr_pointers)); + } else if (OB_FAIL(expr->preorder_accept(*this))) { + LOG_WARN("fail to check group by", K(i), K(ret)); + } + } + + if (OB_SUCC(ret)) { + const ObIArray &child_stmts = ref_stmt->get_set_query(); + for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); ++i) { + ret = check_select_stmt(child_stmts.at(i)); + } + } + } + LOG_DEBUG("check any value end stmt", K(ret)); + return ret; +} + +int ObAnyValueChecker::check_any_value(const ObRawExpr *expr, const ObColumnRefRawExpr *undefined_column) +{ + int ret = OB_SUCCESS; + undefined_column_ = undefined_column; + ObRawExpr *expr_ = const_cast(expr); + if (OB_ISNULL(expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is null"); + } else if (OB_FAIL(expr_->preorder_accept(*this))) { + LOG_WARN("check any value expr fail", K(ret)); + } + return ret; +} + +bool ObAnyValueChecker::is_pass_after_check() +{ + return is_pass_; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/resolver/dml/ob_any_value_checker.h b/src/sql/resolver/dml/ob_any_value_checker.h new file mode 100644 index 0000000000..b4cd8477aa --- /dev/null +++ b/src/sql/resolver/dml/ob_any_value_checker.h @@ -0,0 +1,70 @@ +/** + * Copyright 2014-2021 Alibaba Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * + * Date: 2021/07/14 + * + * ob_any_value_checker.h is for checking any_value expr in mysql's only_full_group_by mode compatible + * + * Authors: + * ailing.lcq + */ + +#ifndef OCEANBASE_SRC_SQL_RESOLVER_DML_OB_ANY_VALUE_CHECKER_H_ +#define OCEANBASE_SRC_SQL_RESOLVER_DML_OB_ANY_VALUE_CHECKER_H_ +#include "sql/resolver/expr/ob_raw_expr.h" +#include "sql/resolver/dml/ob_select_stmt.h" + +namespace oceanbase { +namespace sql { + +class ObAnyValueChecker : public ObRawExprVisitor { +public: + ObAnyValueChecker() : ObRawExprVisitor(), skip_expr_(nullptr), is_pass_(true) + {} + virtual ~ObAnyValueChecker() + {} + /// interface of ObRawExprVisitor + virtual int visit(ObConstRawExpr &expr); + virtual int visit(ObVarRawExpr &expr); + virtual int visit(ObQueryRefRawExpr &expr); + virtual int visit(ObColumnRefRawExpr &expr); + virtual int visit(ObOpRawExpr &expr); + virtual int visit(ObCaseOpRawExpr &expr); + virtual int visit(ObAggFunRawExpr &expr); + virtual int visit(ObSysFunRawExpr &expr); + virtual int visit(ObSetOpRawExpr &expr); + virtual int visit(ObAliasRefRawExpr &expr); + virtual int visit(ObFunMatchAgainst &expr); + virtual int visit(ObWinFunRawExpr &expr); + virtual int visit(ObPseudoColumnRawExpr &expr); + + // set expr skip + virtual bool skip_child(ObRawExpr &expr) + { + return skip_expr_ == &expr; + } + + int check_select_stmt(const ObSelectStmt *ref_stmt); + int check_any_value(const ObRawExpr *expr, const ObColumnRefRawExpr *undefined_column); + bool is_pass_after_check(); + +private: + void set_skip_expr(ObRawExpr *expr) + { + skip_expr_ = expr; + } + const ObColumnRefRawExpr *undefined_column_; + ObRawExpr *skip_expr_; + bool is_pass_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObAnyValueChecker); +}; + +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SRC_SQL_RESOLVER_DML_OB_ANY_VALUE_CHECKER_H_ diff --git a/src/sql/resolver/dml/ob_standard_group_checker.cpp b/src/sql/resolver/dml/ob_standard_group_checker.cpp index a34358c9ff..6ceaa59fa9 100644 --- a/src/sql/resolver/dml/ob_standard_group_checker.cpp +++ b/src/sql/resolver/dml/ob_standard_group_checker.cpp @@ -13,6 +13,7 @@ #define USING_LOG_PREFIX SQL_RESV #include "sql/resolver/dml/ob_standard_group_checker.h" #include "sql/resolver/expr/ob_raw_expr.h" +#include "sql/resolver/dml/ob_any_value_checker.h" namespace oceanbase { using namespace common; namespace sql { @@ -96,7 +97,8 @@ int ObStandardGroupChecker::check_only_full_group_by() // not check aggregate function or column in aggregate function, such as select count(c1) from t1 group by c2; // but if expr has column outside of aggregate function, we only check the column not in aggregate function // such as: select c1+count(c2) from t1 group by c1; - const ObUnsettledExprItem& unsettled_expr = unsettled_exprs_.at(i); + const ObUnsettledExprItem &unsettled_expr = unsettled_exprs_.at(i); + common::ObArray undefined_columns; for (int64_t j = unsettled_expr.start_idx_; OB_SUCC(ret) && j < unsettled_expr.start_idx_ + unsettled_expr.dependent_column_cnt_; ++j) { @@ -110,13 +112,22 @@ int ObStandardGroupChecker::check_only_full_group_by() } else if (OB_FAIL(check_unsettled_column(unsettled_column, undefined_column))) { LOG_WARN("check unsettled column failed", K(ret)); } else if (undefined_column != NULL) { - break; + //当前stmt中存在undefined的列,根据only full group + //by语义,如果一个表达式中所有列都是defined,那么该表达式是defined + //如果所有列不能保证defined,需要看看表达式本身是否是defined + //例如:select c1+c2 from t1 group by c1, c1+c2 + // c1是defined列,c2不是,c1+c2整体是defined,所以这条语句满足only full group by + undefined_columns.push_back(undefined_column); + undefined_column = NULL; } } - if (OB_SUCC(ret) && undefined_column != NULL) { - // has undefined column, must check expr whether defined in group by - if (OB_FAIL(check_unsettled_expr(unsettled_expr.expr_, *undefined_column))) { - LOG_WARN("check unsettled expr failed", K(ret)); + if (OB_SUCC(ret) && 0 != undefined_columns.size()) { + // has undefined column, must check expr whether defined in group by or in any_value + for (int64_t i = 0; OB_SUCC(ret) && i < undefined_columns.size(); ++i) { + if (OB_FAIL(check_unsettled_expr(unsettled_expr.expr_, *(undefined_columns.at(i))))) { + LOG_WARN("check unsettled expr failed", K(ret)); + break; + } } } if (OB_SUCC(ret) && !unsettled_expr.expr_->has_flag(CNT_AGG)) { @@ -180,9 +191,6 @@ int ObStandardGroupChecker::check_unsettled_expr( // but if expr has column outside of aggregate function, we only check the column not in aggregate function // such as: select c1+count(c2) from t1 group by c1; ret = OB_ERR_WRONG_FIELD_WITH_GROUP; - ObString column_name = concat_qualified_name( - undefined_column.get_database_name(), undefined_column.get_table_name(), undefined_column.get_column_name()); - LOG_USER_ERROR(OB_ERR_WRONG_FIELD_WITH_GROUP, column_name.length(), column_name.ptr()); LOG_DEBUG("column not in group by", K(*unsettled_expr), K(undefined_column)); } else if (OB_HASH_EXIST == (ret = settled_columns_.exist_refactored(reinterpret_cast(unsettled_expr)))) { // this expr satisfy the only full group by semantic constraints @@ -201,13 +209,30 @@ int ObStandardGroupChecker::check_unsettled_expr( } if (OB_SUCC(ret) && !is_defined) { ret = OB_ERR_WRONG_FIELD_WITH_GROUP; - ObString column_name = concat_qualified_name( - undefined_column.get_database_name(), undefined_column.get_table_name(), undefined_column.get_column_name()); - LOG_USER_ERROR(OB_ERR_WRONG_FIELD_WITH_GROUP, column_name.length(), column_name.ptr()); } } else { LOG_WARN("check unsettled expr failed", K(ret)); } + + if (OB_ERR_WRONG_FIELD_WITH_GROUP == ret || OB_ERR_MIX_OF_GROUP_FUNC_AND_FIELDS == ret) { + int tmp_ret = ret; + ObAnyValueChecker any_value_checker; + if (OB_FAIL(any_value_checker.check_any_value(unsettled_expr, &undefined_column))) { + LOG_WARN("check any value expr fail", K(ret)); + } else { + if (any_value_checker.is_pass_after_check()) { + ret = OB_SUCCESS; + } else { + ret = tmp_ret; + if (OB_ERR_WRONG_FIELD_WITH_GROUP == ret) { + ObString column_name = concat_qualified_name(undefined_column.get_database_name(), + undefined_column.get_table_name(), + undefined_column.get_column_name()); + LOG_USER_ERROR(OB_ERR_WRONG_FIELD_WITH_GROUP, column_name.length(), column_name.ptr()); + } + } + } + } return ret; } } // namespace sql -- GitLab