From 7e5730a2f313ddc4ed2e80fffd71edb686cee6a6 Mon Sep 17 00:00:00 2001 From: obdev Date: Wed, 2 Nov 2022 23:40:43 +0000 Subject: [PATCH] [to #45186814] fix continue handler in mysql pl --- src/pl/ob_pl_resolver.cpp | 74 ++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/src/pl/ob_pl_resolver.cpp b/src/pl/ob_pl_resolver.cpp index 7fdf144949..36a1156418 100644 --- a/src/pl/ob_pl_resolver.cpp +++ b/src/pl/ob_pl_resolver.cpp @@ -421,7 +421,12 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun LOG_WARN("fail to check decalre order", K(ret)); } else if (OB_FAIL(resolve_declare_handler(parse_tree, static_cast(NULL == stmt ? current_block_->get_eh() : stmt), func))) { LOG_WARN("failed to resolve declare handler stmt", K(parse_tree), K(stmt), K(ret)); - } else { + } else if (stmt != NULL && static_cast(stmt)->get_handlers().count() <= 0) { + // continue handler will record into handler_analyzer_, + // so here handlers may null, do not add null handler to current block. + stmt = NULL; + } + if (OB_SUCC(ret)) { func.set_is_all_sql_stmt(false); } } @@ -645,7 +650,7 @@ int ObPLResolver::resolve(const ObStmtNodeTree *parse_tree, ObPLFunctionAST &fun } if (OB_SUCC(ret) && handler_analyzer_.in_continue() && NULL != stmt && !NO_EXCEPTION_STMT(stmt->get_type())) { - //如果自己在continue里,那么把栈里的handler都加到block里 + // for continue handler, should add handler to every stmt, here, make a new block, consturct new block with handler and stmt. ObPLStmtBlock *block = NULL; if (OB_FAIL(make_block(func, current_block_, block))) { LOG_WARN("failed to make block", K(current_block_), K(ret)); @@ -990,10 +995,22 @@ int ObPLResolver::check_declare_order(ObPLStmtType type) CK(PL_VAR == type || PL_COND == type || PL_HANDLER == type || PL_CURSOR == type); if (is_oracle_mode()) { // oracle compatible, do nothing ... - } else if (OB_NOT_NULL(current_block_) && current_block_->get_stmts().count() != 0) { - ObPLStmtType pre_type = - current_block_->get_stmts().at(current_block_->get_stmts().count() - 1)->get_type(); - if ((PL_VAR == type || PL_COND == type) + } else { + ObPLStmtType pre_type = INVALID_PL_STMT; + if (OB_NOT_NULL(current_block_) && (current_block_->get_stmts().count() != 0)) { + pre_type = + current_block_->get_stmts().at(current_block_->get_stmts().count() - 1)->get_type(); + } + if (handler_analyzer_.get_stack_depth() > 0) { + ObPLDeclareHandlerStmt::DeclareHandler info; + if (OB_FAIL(handler_analyzer_.get_handler(handler_analyzer_.get_stack_depth() - 1, info))) { + LOG_WARN("failed to get last handler", K(ret)); + } else if (info.get_level() == current_level_) { + pre_type = PL_HANDLER; + } + } + if (OB_FAIL(ret)) { + } else if ((PL_VAR == type || PL_COND == type) && (PL_HANDLER == pre_type || PL_CURSOR == pre_type)) { ret = OB_ER_SP_VARCOND_AFTER_CURSHNDLR; LOG_USER_ERROR(OB_ER_SP_VARCOND_AFTER_CURSHNDLR); @@ -5202,15 +5219,16 @@ int ObPLResolver::resolve_declare_handler(const ObStmtNodeTree *parse_tree, ObPL ret = OB_ERR_NO_CHOICES; LOG_WARN("no choices may appear with choice OTHERS in an exception handler", K(ret)); + } else if (OB_FAIL(desc->add_condition(value))) { + LOG_WARN("failed to add condition for delcare handler desc", K(ret), K(value)); } else { - desc->add_condition(value); if (NOT_FOUND == actual_type && !handler_analyzer_.in_notfound()) { handler_analyzer_.set_notfound(current_level_); current_block_->set_notfound(); } else if (SQL_WARNING == actual_type && !handler_analyzer_.in_warning()) { handler_analyzer_.set_warning(current_level_); current_block_->set_warning(); - } else { /*do nothing*/ } + } } } } @@ -5235,17 +5253,19 @@ int ObPLResolver::resolve_declare_handler(const ObStmtNodeTree *parse_tree, ObPL } } - if (OB_SUCC(ret)) { + if (OB_SUCC(ret) && !desc->is_continue()) { ObPLDeclareHandlerStmt::DeclareHandler handler; handler.set_desc(desc); - OZ (stmt->add_handler(handler)); + if (OB_FAIL(stmt->add_handler(handler))) { + LOG_WARN("failed to add handler", K(ret)); + } } if (OB_SUCC(ret)) { if (OB_ISNULL(current_block_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Symbol table is NULL", K(current_block_), K(ret)); - } else { + } else if (stmt->get_handlers().count() > 0) { current_block_->set_eh(stmt); } } @@ -12194,7 +12214,7 @@ int ObPLResolver::check_duplicate_condition(const ObPLDeclareHandlerStmt &stmt, { int ret = OB_SUCCESS; dup = false; - for (int64_t i = 0; !dup && i < stmt.get_handlers().count(); ++i) { + for (int64_t i = 0; OB_SUCC(ret) && !dup && i < stmt.get_handlers().count(); ++i) { ObPLDeclareHandlerStmt::DeclareHandler::HandlerDesc *desc = stmt.get_handler(i).get_desc(); if (OB_ISNULL(desc)) { ret = OB_ERR_UNEXPECTED; @@ -12210,6 +12230,29 @@ int ObPLResolver::check_duplicate_condition(const ObPLDeclareHandlerStmt &stmt, } } } + for (int64_t i = handler_analyzer_.get_stack_depth() - 1; OB_SUCC(ret) && !dup && i >= 0; --i) { + ObPLDeclareHandlerStmt::DeclareHandler handler; + if (OB_FAIL(handler_analyzer_.get_handler(i, handler))) { + LOG_WARN("failed to get handler from handler analyzer", K(ret), K(i)); + } else if (handler.get_level() == current_level_) { + ObPLDeclareHandlerStmt::DeclareHandler::HandlerDesc *desc = handler.get_desc(); + if (OB_ISNULL(desc)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Handler desc is NULL", K(ret), K(i), K(handler)); + } else if (desc->is_continue()) { + for (int64_t j = 0; !dup && j < desc->get_conditions().count(); ++j) { + if (value.type_ == desc->get_condition(j).type_ && + value.error_code_ == desc->get_condition(j).error_code_ && + value.str_len_ == desc->get_condition(j).str_len_ && + 0 == STRNCMP(value.sql_state_, desc->get_condition(j).sql_state_, value.str_len_)) { + dup = true; + } + } + } + } else { + break; + } + } return ret; } @@ -12431,7 +12474,12 @@ int ObPLResolver::HandlerAnalyzer::reset_handlers(int64_t level) int ret = OB_SUCCESS; for (int64_t i = handler_stack_.count() - 1; OB_SUCC(ret) && i >= 0; --i) { if (handler_stack_.at(i).get_level() == level) { - handler_stack_.pop_back(); + if (i != handler_stack_.count() -1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to reset handlers with level", K(ret), K(level), K(i), K(handler_stack_.at(i))); + } else { + handler_stack_.pop_back(); + } } } if (OB_SUCC(ret) && handler_stack_.count() - 1 < top_continue_) {