[CP] [CP] issue<50775099>:forbid set global var when executing nested sql

This commit is contained in:
hanr881
2023-07-25 07:48:39 +00:00
committed by ob-robot
parent e4ac16a787
commit 5c2fc55d63
3 changed files with 57 additions and 13 deletions

View File

@ -225,9 +225,46 @@ int ObSPIResultSet::alloc_saved_value(sql::ObSQLSessionInfo::StmtSavedValue *&se
return ret;
}
int ObSPIResultSet::check_nested_stmt_legal(ObExecContext &exec_ctx, stmt::StmtType stmt_type, bool for_update)
int ObSPIResultSet::is_set_global_var(ObSQLSessionInfo &session, const ObString &sql, bool &has_global_variable)
{
int ret = OB_SUCCESS;
has_global_variable = false;
ObArenaAllocator allocator;
ParseResult parse_result;
ParseMode parse_mode = STD_MODE;
ObParser parser(allocator, session.get_sql_mode(), session.get_local_collation_connection());
if (sql.empty()) {
} else if (OB_FAIL(parser.parse(sql,
parse_result,
parse_mode,
false/*is_batched_multi_stmt_split_on*/,
false/*no_throw_parser_error*/,
true))) {
LOG_WARN("generate syntax tree failed", K(sql), K(ret));
} else if (OB_NOT_NULL(parse_result.result_tree_) &&
parse_result.result_tree_->num_child_ > 0 &&
OB_NOT_NULL(parse_result.result_tree_->children_[0])) {
ParseNode *set_node = NULL;
ParseNode *parse_tree = parse_result.result_tree_->children_[0];
for (int64_t i = 0; OB_SUCC(ret) && !has_global_variable && i < parse_tree->num_child_; ++i) {
if (OB_ISNULL(set_node = parse_tree->children_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("set node is NULL", K(ret));
} else if (OB_UNLIKELY(T_VAR_VAL != set_node->type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("set_node->type_ must be T_VAR_VAL", K(ret), K(set_node->type_));
} else if (1 == set_node->value_) { // global var
has_global_variable = true;
}
}
}
return ret;
}
int ObSPIResultSet::check_nested_stmt_legal(ObExecContext &exec_ctx, const ObString &sql, stmt::StmtType stmt_type, bool for_update)
{
int ret = OB_SUCCESS;
bool has_global_variable = false;
stmt::StmtType parent_stmt_type = stmt::T_NONE;
ObSqlCtx *sql_ctx = exec_ctx.get_sql_ctx();
ObPLContext *pl_ctx = exec_ctx.get_pl_stack_ctx();
@ -238,6 +275,9 @@ int ObSPIResultSet::check_nested_stmt_legal(ObExecContext &exec_ctx, stmt::StmtT
parent_stmt_type = sql_ctx->stmt_type_;
LOG_DEBUG("check nested stmt legal", K(parent_stmt_type), K(pl_ctx->in_autonomous()), K(stmt_type));
}
if (stmt::T_VARIABLE_SET == stmt_type && OB_NOT_NULL(exec_ctx.get_my_session())) {
OZ (is_set_global_var(*exec_ctx.get_my_session(), sql, has_global_variable));
}
if (OB_SUCC(ret) && !pl_ctx->in_autonomous() && ObStmt::is_dml_stmt(parent_stmt_type)) {
//only when parent stmt is dml or select, it can trigger a nested sql
if (parent_stmt_type == stmt::T_SELECT && ObStmt::is_dml_write_stmt(stmt_type)) {
@ -262,7 +302,7 @@ int ObSPIResultSet::check_nested_stmt_legal(ObExecContext &exec_ctx, stmt::StmtT
LOG_WARN("ORA-14551: cannot perform a DML operation inside a query",
K(ret), K(stmt_type), K(exec_ctx.get_sql_ctx()),
K(&exec_ctx), K(exec_ctx.get_my_session()->get_cur_exec_ctx()));
} else if (ObStmt::is_ddl_stmt(stmt_type, false) || ObStmt::is_tcl_stmt(stmt_type)) {
} else if (ObStmt::is_ddl_stmt(stmt_type, has_global_variable) || ObStmt::is_tcl_stmt(stmt_type)) {
ret = lib::is_oracle_mode() ? OB_NOT_SUPPORTED : OB_ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG;
LOG_WARN("ORA-14552: Cannot Perform a DDL Commit or Rollback Inside a Query or DML tips",
K(ret), K(stmt_type), K(lbt()));
@ -358,7 +398,7 @@ void ObSPIResultSet::end_cursor_stmt(ObPLExecCtx *pl_ctx, int &result)
return;
}
int ObSPIResultSet::start_nested_stmt_if_need(ObPLExecCtx *pl_ctx, stmt::StmtType stmt_type, bool for_update)
int ObSPIResultSet::start_nested_stmt_if_need(ObPLExecCtx *pl_ctx, const ObString &sql, stmt::StmtType stmt_type, bool for_update)
{
int ret = OB_SUCCESS;
ObSQLSessionInfo *session = NULL;
@ -371,7 +411,7 @@ int ObSPIResultSet::start_nested_stmt_if_need(ObPLExecCtx *pl_ctx, stmt::StmtTyp
} else if (OB_NOT_NULL(pl_ctx->exec_ctx_->get_pl_stack_ctx())
&& pl_ctx->exec_ctx_->get_pl_stack_ctx()->in_nested_sql_ctrl()) {
// 嵌套的顶层语句一定是一个DML语句, 并且开启了事务, 此时走fast_select流程
OZ (check_nested_stmt_legal(*pl_ctx->exec_ctx_, stmt_type, for_update));
OZ (check_nested_stmt_legal(*pl_ctx->exec_ctx_, sql, stmt_type, for_update));
OZ (begin_nested_session(*session));
OX (session->set_query_start_time(ObTimeUtility::current_time()));
OX (need_end_nested_stmt_ = EST_END_NESTED_SESSION);
@ -1313,7 +1353,8 @@ int ObSPIService::spi_end_trans(ObPLExecCtx *ctx, const char *sql, bool is_rollb
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("session ptr is null", K(ret));
} else {
OZ (ObSPIResultSet::check_nested_stmt_legal(*(ctx->exec_ctx_), stmt::T_END_TRANS));
ObString sqlstr(sql);
OZ (ObSPIResultSet::check_nested_stmt_legal(*(ctx->exec_ctx_), sqlstr, stmt::T_END_TRANS));
int64_t saved_query_start_time = my_session->get_query_start_time();
my_session->set_query_start_time(ObTimeUtility::current_time());
if (OB_SUCC(ret)) {
@ -1432,8 +1473,9 @@ int ObSPIService::spi_inner_execute(ObPLExecCtx *ctx,
HEAP_VAR(ObSPIResultSet, spi_result) {
stmt::StmtType stmt_type = stmt::T_NONE;
bool is_diagnostics_stmt = false;
ObString sqlstr(sql);
OZ (spi_result.init(*session));
OZ (spi_result.start_nested_stmt_if_need(ctx, static_cast<stmt::StmtType>(type), for_update));
OZ (spi_result.start_nested_stmt_if_need(ctx, sqlstr, static_cast<stmt::StmtType>(type), for_update));
if (OB_SUCC(ret)) {
int64_t row_count = 0;
@ -1655,7 +1697,7 @@ int ObSPIService::dbms_cursor_execute(ObPLExecCtx *ctx,
HEAP_VAR(ObSPIResultSet, spi_result) {
OZ (spi_result.init(*session));
OZ (spi_result.start_nested_stmt_if_need(ctx, static_cast<stmt::StmtType>(stmt_type), cursor.is_for_update()));
OZ (spi_result.start_nested_stmt_if_need(ctx, sql_stmt, static_cast<stmt::StmtType>(stmt_type), cursor.is_for_update()));
if (OB_SUCC(ret)) {
int64_t row_count = 0;
ObQueryRetryCtrl retry_ctrl;
@ -2600,7 +2642,7 @@ int ObSPIService::spi_execute_immediate(ObPLExecCtx *ctx,
}
}
OX (session->set_stmt_type(saved_stmt_type));
OZ (spi_result.start_nested_stmt_if_need(ctx, stmt_type, for_update));
OZ (spi_result.start_nested_stmt_if_need(ctx, sql_str.string(), stmt_type, for_update));
// Step2: execute dynamic SQL now!
if (OB_FAIL(ret)) {
@ -3472,8 +3514,9 @@ int ObSPIService::spi_cursor_open(ObPLExecCtx *ctx,
cursor->set_last_execute_time(ObTimeUtility::current_time());
} else { //MySQL Cursor/Updated Cursor/Server Cursor(REF_CURSOR, PACKAGE CURSOR)
HEAP_VAR(ObSPIResultSet, spi_result) {
ObString sqlstr(sql);
OZ (spi_result.init(*session_info));
OZ (spi_result.start_nested_stmt_if_need(ctx, static_cast<stmt::StmtType>(type), for_update));
OZ (spi_result.start_nested_stmt_if_need(ctx, sqlstr, static_cast<stmt::StmtType>(type), for_update));
int64_t old_query_start_time = session_info->get_query_start_time();
// query_start_time_ set to 0 in begin_nested_session, here we reset it.
session_info->set_query_start_time(ObTimeUtility::current_time());
@ -3746,7 +3789,7 @@ int ObSPIService::dbms_cursor_open(ObPLExecCtx *ctx,
uint64_t size = 0;
OZ (session->get_tmp_table_size(size));
OZ (spi_result.init(*ctx->exec_ctx_->get_my_session()));
OZ (spi_result.start_nested_stmt_if_need(ctx, static_cast<stmt::StmtType>(stmt_type), for_update),
OZ (spi_result.start_nested_stmt_if_need(ctx, sql_stmt, static_cast<stmt::StmtType>(stmt_type), for_update),
sql_stmt, ps_sql, exec_params);
if (OB_SUCC(ret)) {