From d6fa144191478635f21563518a57ba839567d3db Mon Sep 17 00:00:00 2001 From: st0 Date: Mon, 24 Jan 2022 15:57:49 +0800 Subject: [PATCH] fix CTE in mysql mode bug --- src/share/gen_errno.pl | 1 + src/share/ob_errno.cpp | 4 ++- src/share/ob_errno.def | 2 +- src/sql/ob_select_stmt_printer.cpp | 2 +- src/sql/optimizer/ob_optimizer_util.cpp | 18 ++++++---- src/sql/optimizer/ob_optimizer_util.h | 8 +++-- src/sql/resolver/dml/ob_select_resolver.cpp | 38 ++++++++++++++------- src/sql/resolver/ob_resolver_define.h | 4 +-- 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/share/gen_errno.pl b/src/share/gen_errno.pl index 8ed9831f6e..fb57581031 100755 --- a/src/share/gen_errno.pl +++ b/src/share/gen_errno.pl @@ -201,6 +201,7 @@ print $fh_header '/** * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ + // DO NOT EDIT. This file is automatically generated from `ob_errno.def\'. #ifndef OCEANBASE_LIB_OB_ERRNO_H_ diff --git a/src/share/ob_errno.cpp b/src/share/ob_errno.cpp index a741394a48..1a8681ded7 100644 --- a/src/share/ob_errno.cpp +++ b/src/share/ob_errno.cpp @@ -12101,7 +12101,7 @@ static struct ObStrErrorInit ERROR_NAME[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "OB_ERR_CTE_NEED_QUERY_BLOCKS"; ERROR_CAUSE[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Internal Error"; ERROR_SOLUTION[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Contact OceanBase Support"; - MYSQL_ERRNO[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = -1; + MYSQL_ERRNO[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = 3574; SQLSTATE[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "HY000"; STR_ERROR[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones"; STR_USER_ERROR[-OB_ERR_CTE_NEED_QUERY_BLOCKS] = "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s"; @@ -14009,6 +14009,8 @@ static struct ObStrErrorInit ORACLE_STR_ERROR[-OB_ARCHIVE_LOG_NOT_CONTINUES_WITH_DATA] = "ORA-00600: internal error code, arguments: -9064, the archive log and backup data are not continuous"; ORACLE_STR_USER_ERROR[-OB_ARCHIVE_LOG_NOT_CONTINUES_WITH_DATA] = "ORA-00600: internal error code, arguments: -9064, the archive log and backup data are not continuous"; ERROR_NAME[-OB_BACKUP_DELETE_BACKUP_PIECE_NOT_ALLOWED] = "OB_BACKUP_DELETE_BACKUP_PIECE_NOT_ALLOWED"; + ERROR_CAUSE[-OB_BACKUP_DELETE_BACKUP_PIECE_NOT_ALLOWED] = "Internal Error"; + ERROR_SOLUTION[-OB_BACKUP_DELETE_BACKUP_PIECE_NOT_ALLOWED] = "Contact OceanBase Support"; MYSQL_ERRNO[-OB_BACKUP_DELETE_BACKUP_PIECE_NOT_ALLOWED] = -1; SQLSTATE[-OB_BACKUP_DELETE_BACKUP_PIECE_NOT_ALLOWED] = "HY000"; STR_ERROR[-OB_BACKUP_DELETE_BACKUP_PIECE_NOT_ALLOWED] = "deleting backup piece is not allowed"; diff --git a/src/share/ob_errno.def b/src/share/ob_errno.def index 89e14c87ef..f9a1389ba6 100644 --- a/src/share/ob_errno.def +++ b/src/share/ob_errno.def @@ -1325,7 +1325,7 @@ DEFINE_ERROR_EXT(OB_ERR_WINDOW_NAME_IS_NOT_DEFINE, -5929, -1, "HY000", "Window n DEFINE_ORACLE_ERROR(OB_ERR_OPEN_CURSORS_EXCEEDED, -5930, -1, "HY000", "maximum open cursors exceeded", 1000, "maximum open cursors exceeded"); DEFINE_ORACLE_ERROR(OB_ERR_ARG_INVALID, -5931, -1, "HY000", "argument is null, invalid, or out of range", 21560, "argument %.*s is null, invalid, or out of range"); DEFINE_ORACLE_ERROR(OB_ERR_ILL_NAME_STRING, -5932, -1, "HY000", "unexpected name string", 21560, "unexpected name string '%.*s'"); -DEFINE_ERROR_EXT(OB_ERR_CTE_NEED_QUERY_BLOCKS, -5976, -1, "HY000", "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones", "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s"); +DEFINE_ERROR_EXT(OB_ERR_CTE_NEED_QUERY_BLOCKS, -5976, 3574, "HY000", "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones", "Recursive Common Table Expression should have one or more non-recursive query blocks followed by one or more recursive ones: %s"); DEFINE_ERROR_EXT(OB_ERR_INCORRECT_VALUE_FOR_FUNCTION, -5936, ER_WRONG_VALUE_FOR_TYPE, "HY000", "Incorrect value for function", "Incorrect %.*s value: '%.*s' for function %.*s"); DEFINE_ERROR_EXT(OB_ERR_USER_EXCEED_RESOURCE, -5967, 1226, "42000", "User has exceeded the resource", "User '%.*s' has exceeded the '%s' resource (current value: %lu)"); diff --git a/src/sql/ob_select_stmt_printer.cpp b/src/sql/ob_select_stmt_printer.cpp index a110b7e243..19967948ba 100644 --- a/src/sql/ob_select_stmt_printer.cpp +++ b/src/sql/ob_select_stmt_printer.cpp @@ -825,7 +825,7 @@ int ObSelectStmtPrinter::print_for_update() int ObSelectStmtPrinter::print_with() { int ret = OB_SUCCESS; - DATA_PRINTF("WITH "); + DATA_PRINTF(is_oracle_mode() ? "WITH " : "WITH RECURSIVE"); if (OB_SUCC(ret)) { const ObSelectStmt* select_stmt = static_cast(stmt_); const common::ObIArray& cte_tables = select_stmt->get_CTE_table_items(); diff --git a/src/sql/optimizer/ob_optimizer_util.cpp b/src/sql/optimizer/ob_optimizer_util.cpp index 4c647e16b5..abef3f5589 100644 --- a/src/sql/optimizer/ob_optimizer_util.cpp +++ b/src/sql/optimizer/ob_optimizer_util.cpp @@ -4816,15 +4816,16 @@ int ObOptimizerUtil::is_lossless_column_cast(const ObRawExpr* expr, bool& is_los } int ObOptimizerUtil::gen_set_target_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, - ObRawExprFactory* expr_factory, ObSelectStmt& left_stmt, ObSelectStmt& right_stmt, ObSelectStmt* select_stmt) + ObRawExprFactory* expr_factory, ObSelectStmt& left_stmt, ObSelectStmt& right_stmt, + ObSelectStmt* select_stmt, const bool to_left_type /* false */) { int ret = OB_SUCCESS; ObSEArray left_stmts; ObSEArray right_stmts; if (OB_FAIL(left_stmts.push_back(&left_stmt)) || OB_FAIL(right_stmts.push_back(&right_stmt))) { LOG_WARN("failed to pushback stmt", K(ret)); - } else if (OB_FAIL( - gen_set_target_list(allocator, session_info, expr_factory, left_stmts, right_stmts, select_stmt))) { + } else if (OB_FAIL(gen_set_target_list( + allocator, session_info, expr_factory, left_stmts, right_stmts, select_stmt, to_left_type))) { LOG_WARN("failed to get set target list", K(ret)); } return ret; @@ -4832,7 +4833,7 @@ int ObOptimizerUtil::gen_set_target_list(ObIAllocator* allocator, ObSQLSessionIn int ObOptimizerUtil::gen_set_target_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObIArray& left_stmts, ObIArray& right_stmts, - ObSelectStmt* select_stmt) + ObSelectStmt* select_stmt, const bool to_left_type /* false */) { int ret = OB_SUCCESS; UNUSED(allocator); @@ -4847,7 +4848,8 @@ int ObOptimizerUtil::gen_set_target_list(ObIAllocator* allocator, ObSQLSessionIn select_stmt->is_set_distinct(), left_stmts, right_stmts, - &res_types))) { + &res_types, + to_left_type))) { LOG_WARN("failed to try add cast to set child list", K(ret)); } else if (OB_ISNULL(child_stmt = select_stmt->get_set_query(0)) || OB_UNLIKELY(res_types.count() != child_stmt->get_select_item_size())) { @@ -5031,7 +5033,7 @@ int ObOptimizerUtil::get_set_res_types(ObIAllocator* allocator, ObSQLSessionInfo int ObOptimizerUtil::try_add_cast_to_set_child_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, const bool is_distinct, ObIArray& left_stmts, - ObIArray& right_stmts, ObIArray* res_types) + ObIArray& right_stmts, ObIArray* res_types, const bool to_left_type /* false */) { int ret = OB_SUCCESS; ObExprResType res_type; @@ -5107,6 +5109,8 @@ int ObOptimizerUtil::try_add_cast_to_set_child_list(ObIAllocator* allocator, ObS } const ObLengthSemantics length_semantics = session_info->get_actual_nls_length_semantics(); if (OB_FAIL(ret)) { + } else if (to_left_type) { + res_type = left_type; } else if (OB_FAIL(types.push_back(left_type)) || OB_FAIL(types.push_back(right_type))) { LOG_WARN("failed to push back", K(ret)); } else if (OB_FAIL(session_info->get_collation_connection(coll_type))) { @@ -5114,6 +5118,8 @@ int ObOptimizerUtil::try_add_cast_to_set_child_list(ObIAllocator* allocator, ObS } else if (OB_FAIL(dummy_op.aggregate_result_type_for_merge( res_type, &types.at(0), 2, coll_type, is_oracle_mode(), length_semantics, session_info))) { LOG_WARN("failed to aggregate result type for merge", K(ret)); + } + if (OB_FAIL(ret)) { } else if (ObMaxType == res_type.get_type()) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("column type incompatible", K(left_type), K(right_type)); diff --git a/src/sql/optimizer/ob_optimizer_util.h b/src/sql/optimizer/ob_optimizer_util.h index 296bb920ed..685055f494 100644 --- a/src/sql/optimizer/ob_optimizer_util.h +++ b/src/sql/optimizer/ob_optimizer_util.h @@ -588,11 +588,12 @@ public: static int is_lossless_column_cast(const ObRawExpr* expr, bool& is_lossless); static int gen_set_target_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, - ObRawExprFactory* expr_factory, ObSelectStmt& left_stmt, ObSelectStmt& right_stmt, ObSelectStmt* select_stmt); + ObRawExprFactory* expr_factory, ObSelectStmt& left_stmt, ObSelectStmt& right_stmt, + ObSelectStmt* select_stmt, const bool to_left_type = false); static int gen_set_target_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObIArray& left_stmts, ObIArray& right_stmts, - ObSelectStmt* select_stmt); + ObSelectStmt* select_stmt, const bool to_left_type = false); static int gen_set_target_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObSelectStmt* select_stmt); @@ -602,7 +603,8 @@ public: static int try_add_cast_to_set_child_list(ObIAllocator* allocator, ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, const bool is_distinct, ObIArray& left_stmts, - ObIArray& right_stmts, ObIArray* res_types); + ObIArray& right_stmts, ObIArray* res_types, + const bool to_left_type = false); static int add_cast_to_set_list(ObSQLSessionInfo* session_info, ObRawExprFactory* expr_factory, ObIArray& stmts, const ObExprResType& res_type, const int64_t idx); diff --git a/src/sql/resolver/dml/ob_select_resolver.cpp b/src/sql/resolver/dml/ob_select_resolver.cpp index 78c8890f04..ffdaef2464 100644 --- a/src/sql/resolver/dml/ob_select_resolver.cpp +++ b/src/sql/resolver/dml/ob_select_resolver.cpp @@ -172,8 +172,13 @@ int ObSelectResolver::do_resolve_set_query_in_cte(const ParseNode& parse_tree) select_stmt->add_set_query(left_select_stmt); select_stmt->add_set_query(right_select_stmt); select_stmt->set_calc_found_rows(left_select_stmt->is_calc_found_rows()); - if (OB_FAIL(ObOptimizerUtil::gen_set_target_list( - allocator_, session_info_, params_.expr_factory_, *left_select_stmt, *right_select_stmt, select_stmt))) { + if (OB_FAIL(ObOptimizerUtil::gen_set_target_list(allocator_, + session_info_, + params_.expr_factory_, + *left_select_stmt, + *right_select_stmt, + select_stmt, + !is_oracle_mode()))) { LOG_WARN("failed to gen set target list.", K(ret)); } else if (!right_resolver.cte_ctx_.is_recursive()) { /*do nothing*/ @@ -2169,9 +2174,9 @@ int ObSelectResolver::resolve_with_clause(const ParseNode* node, bool same_level } else { int num_child = node->num_child_; if (node->value_ == 0) - params_.has_recursive_word = false; + params_.has_recursive_word_ = false; else - params_.has_recursive_word = true; + params_.has_recursive_word_ = true; for (int64_t i = 0; OB_SUCC(ret) && i < num_child; ++i) { // alias tblname [(alia colname1, alia colname2)](subquery) [search clause][cycle clause] ParseNode* child_node = node->children_[i]; @@ -2186,7 +2191,13 @@ int ObSelectResolver::resolve_with_clause(const ParseNode* node, bool same_level if (OB_FAIL(select_stmt->check_CTE_name_exist(table_name, duplicate_name))) { LOG_WARN("check cte name failed", K(ret)); } else if (duplicate_name) { - // do nothing, oracle ignore the same define cte name. + if (is_oracle_mode()) { + // do nothing, oracle ignore the same define cte name. + } else { + ret = OB_ERR_NONUNIQ_TABLE; + LOG_WARN("not unique cte table name", K(ret)); + LOG_USER_ERROR(OB_ERR_NONUNIQ_TABLE, table_name.length(), table_name.ptr()); + } } else if (OB_FAIL(resolve_with_clause_subquery(*child_node, table_item))) { LOG_WARN("resolver with_clause_as's subquery failed", K(ret)); } else if (OB_FAIL(select_stmt->add_cte_table_item(table_item, duplicate_name))) { @@ -3132,10 +3143,7 @@ int ObSelectResolver::resolve_recursive_cte_table(const ParseNode& parse_tree, T { int ret = OB_SUCCESS; ObSelectStmt* base_stmt = cte_ctx_.left_select_stmt_; - if (cte_ctx_.cte_col_names_.empty()) { - ret = OB_ERR_NEED_COLUMN_ALIAS_LIST_IN_RECURSIVE_CTE; - LOG_WARN("recursive WITH clause must have column alias list", K(ret)); - } else if (OB_ISNULL(base_stmt) && cte_ctx_.is_set_left_resolver_) { + if (OB_ISNULL(base_stmt) && cte_ctx_.is_set_left_resolver_) { ret = OB_ERR_NEED_INIT_BRANCH_IN_RECURSIVE_CTE; LOG_WARN("recursive WITH clause needs an initialization branch", K(ret)); } else if (OB_ISNULL(base_stmt)) { @@ -3318,8 +3326,11 @@ int ObSelectResolver::resolve_basic_table(const ParseNode& parse_tree, TableItem ObString tblname(table_node->str_len_, table_node->str_value_); if (cte_ctx_.is_with_resolver() && ObCharset::case_insensitive_equal(cte_ctx_.current_cte_table_name_, tblname) && tblname.length() && no_defined_database_name) { - TableItem* item = NULL; - if (OB_FAIL(resolve_recursive_cte_table(parse_tree, item))) { + TableItem *item = NULL; + if (!params_.has_recursive_word_) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("cte table shows in union stmt without recursive keyword", K(ret)); + } else if (OB_FAIL(resolve_recursive_cte_table(parse_tree, item))) { LOG_WARN("revolve recursive set query's right child failed", K(ret)); } else if (cte_ctx_.more_than_two_branch()) { ret = OB_ERR_NEED_ONLY_TWO_BRANCH_IN_RECURSIVE_CTE; @@ -5504,9 +5515,12 @@ int ObSelectResolver::identify_anchor_member( need_swap_childa = true; if (is_oracle_mode()){ ret = OB_SUCCESS; - } else if (params_.has_recursive_word) { + } else if (params_.has_recursive_word_) { ret = OB_ERR_CTE_NEED_QUERY_BLOCKS; // mysql error: Recursive Common Table Expression 'cte' should have one or // more non-recursive query blocks followed by one or more recursive ones + } else { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("cte table shows in left union stmt without recursive keyword", K(ret)); } } else { LOG_WARN("Failed to find anchor member", K(ret)); diff --git a/src/sql/resolver/ob_resolver_define.h b/src/sql/resolver/ob_resolver_define.h index 63a4b76bb4..d3555c6608 100644 --- a/src/sql/resolver/ob_resolver_define.h +++ b/src/sql/resolver/ob_resolver_define.h @@ -288,7 +288,7 @@ struct ObResolverParams { is_multi_table_insert_(false), is_resolve_table_function_expr_(false), has_cte_param_list_(false), - has_recursive_word(false), + has_recursive_word_(false), is_column_ref_(true) {} bool is_force_trace_log() @@ -343,7 +343,7 @@ public: bool is_multi_table_insert_; // used to mark is multi table insert bool is_resolve_table_function_expr_; // used to mark resolve table function expr. bool has_cte_param_list_; - bool has_recursive_word; + bool has_recursive_word_; bool is_column_ref_; // used to mark normal column ref }; } // end namespace sql -- GitLab