[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

@ -159,7 +159,7 @@ int ObExprOpSubQueryInPl::eval_subquery(const ObExpr &expr,
SMART_VAR(ObSPIResultSet, spi_result) { SMART_VAR(ObSPIResultSet, spi_result) {
OZ (spi_result.init(*session)); OZ (spi_result.init(*session));
OZ (spi_result.start_nested_stmt_if_need(&pl_exec_ctx, static_cast<stmt::StmtType>(info->type_), false)); OZ (spi_result.start_nested_stmt_if_need(&pl_exec_ctx, info->route_sql_, static_cast<stmt::StmtType>(info->type_), false));
if (OB_SUCC(ret)) { if (OB_SUCC(ret)) {
ObSPIOutParams out_params; ObSPIOutParams out_params;

View File

@ -225,9 +225,46 @@ int ObSPIResultSet::alloc_saved_value(sql::ObSQLSessionInfo::StmtSavedValue *&se
return ret; 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; 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; stmt::StmtType parent_stmt_type = stmt::T_NONE;
ObSqlCtx *sql_ctx = exec_ctx.get_sql_ctx(); ObSqlCtx *sql_ctx = exec_ctx.get_sql_ctx();
ObPLContext *pl_ctx = exec_ctx.get_pl_stack_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_; 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)); 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)) { 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 //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)) { 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", LOG_WARN("ORA-14551: cannot perform a DML operation inside a query",
K(ret), K(stmt_type), K(exec_ctx.get_sql_ctx()), K(ret), K(stmt_type), K(exec_ctx.get_sql_ctx()),
K(&exec_ctx), K(exec_ctx.get_my_session()->get_cur_exec_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; 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", LOG_WARN("ORA-14552: Cannot Perform a DDL Commit or Rollback Inside a Query or DML tips",
K(ret), K(stmt_type), K(lbt())); K(ret), K(stmt_type), K(lbt()));
@ -358,7 +398,7 @@ void ObSPIResultSet::end_cursor_stmt(ObPLExecCtx *pl_ctx, int &result)
return; 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; int ret = OB_SUCCESS;
ObSQLSessionInfo *session = NULL; 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()) } 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()) { && pl_ctx->exec_ctx_->get_pl_stack_ctx()->in_nested_sql_ctrl()) {
// 嵌套的顶层语句一定是一个DML语句, 并且开启了事务, 此时走fast_select流程 // 嵌套的顶层语句一定是一个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)); OZ (begin_nested_session(*session));
OX (session->set_query_start_time(ObTimeUtility::current_time())); OX (session->set_query_start_time(ObTimeUtility::current_time()));
OX (need_end_nested_stmt_ = EST_END_NESTED_SESSION); 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; ret = OB_ERR_UNEXPECTED;
LOG_ERROR("session ptr is null", K(ret)); LOG_ERROR("session ptr is null", K(ret));
} else { } 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(); int64_t saved_query_start_time = my_session->get_query_start_time();
my_session->set_query_start_time(ObTimeUtility::current_time()); my_session->set_query_start_time(ObTimeUtility::current_time());
if (OB_SUCC(ret)) { if (OB_SUCC(ret)) {
@ -1432,8 +1473,9 @@ int ObSPIService::spi_inner_execute(ObPLExecCtx *ctx,
HEAP_VAR(ObSPIResultSet, spi_result) { HEAP_VAR(ObSPIResultSet, spi_result) {
stmt::StmtType stmt_type = stmt::T_NONE; stmt::StmtType stmt_type = stmt::T_NONE;
bool is_diagnostics_stmt = false; bool is_diagnostics_stmt = false;
ObString sqlstr(sql);
OZ (spi_result.init(*session)); 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)) { if (OB_SUCC(ret)) {
int64_t row_count = 0; int64_t row_count = 0;
@ -1655,7 +1697,7 @@ int ObSPIService::dbms_cursor_execute(ObPLExecCtx *ctx,
HEAP_VAR(ObSPIResultSet, spi_result) { HEAP_VAR(ObSPIResultSet, spi_result) {
OZ (spi_result.init(*session)); 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)) { if (OB_SUCC(ret)) {
int64_t row_count = 0; int64_t row_count = 0;
ObQueryRetryCtrl retry_ctrl; ObQueryRetryCtrl retry_ctrl;
@ -2600,7 +2642,7 @@ int ObSPIService::spi_execute_immediate(ObPLExecCtx *ctx,
} }
} }
OX (session->set_stmt_type(saved_stmt_type)); 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! // Step2: execute dynamic SQL now!
if (OB_FAIL(ret)) { if (OB_FAIL(ret)) {
@ -3472,8 +3514,9 @@ int ObSPIService::spi_cursor_open(ObPLExecCtx *ctx,
cursor->set_last_execute_time(ObTimeUtility::current_time()); cursor->set_last_execute_time(ObTimeUtility::current_time());
} else { //MySQL Cursor/Updated Cursor/Server Cursor(REF_CURSOR, PACKAGE CURSOR) } else { //MySQL Cursor/Updated Cursor/Server Cursor(REF_CURSOR, PACKAGE CURSOR)
HEAP_VAR(ObSPIResultSet, spi_result) { HEAP_VAR(ObSPIResultSet, spi_result) {
ObString sqlstr(sql);
OZ (spi_result.init(*session_info)); 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(); 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. // query_start_time_ set to 0 in begin_nested_session, here we reset it.
session_info->set_query_start_time(ObTimeUtility::current_time()); session_info->set_query_start_time(ObTimeUtility::current_time());
@ -3746,7 +3789,7 @@ int ObSPIService::dbms_cursor_open(ObPLExecCtx *ctx,
uint64_t size = 0; uint64_t size = 0;
OZ (session->get_tmp_table_size(size)); OZ (session->get_tmp_table_size(size));
OZ (spi_result.init(*ctx->exec_ctx_->get_my_session())); 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); sql_stmt, ps_sql, exec_params);
if (OB_SUCC(ret)) { if (OB_SUCC(ret)) {

View File

@ -187,7 +187,8 @@ private:
int end_nested_session(ObSQLSessionInfo &session); int end_nested_session(ObSQLSessionInfo &session);
int alloc_saved_value(sql::ObSQLSessionInfo::StmtSavedValue *&session_value); int alloc_saved_value(sql::ObSQLSessionInfo::StmtSavedValue *&session_value);
public: public:
static int check_nested_stmt_legal(ObExecContext &exec_ctx, stmt::StmtType stmt_type, bool for_update = false); static int is_set_global_var(ObSQLSessionInfo &session, const ObString &sql, bool &has_global_variable);
static int check_nested_stmt_legal(ObExecContext &exec_ctx, const ObString &sql, stmt::StmtType stmt_type, bool for_update = false);
int start_trans(ObExecContext &ctx); int start_trans(ObExecContext &ctx);
int set_cursor_env(ObSQLSessionInfo &session); int set_cursor_env(ObSQLSessionInfo &session);
int reset_cursor_env(ObSQLSessionInfo &session); int reset_cursor_env(ObSQLSessionInfo &session);
@ -195,7 +196,7 @@ public:
stmt::StmtType type = stmt::StmtType::T_NONE, stmt::StmtType type = stmt::StmtType::T_NONE,
bool is_for_update = false); bool is_for_update = false);
void end_cursor_stmt(pl::ObPLExecCtx *pl_ctx, int &result); void end_cursor_stmt(pl::ObPLExecCtx *pl_ctx, int &result);
int start_nested_stmt_if_need(pl::ObPLExecCtx *pl_ctx, stmt::StmtType stmt_type, bool for_update); int start_nested_stmt_if_need(pl::ObPLExecCtx *pl_ctx, const ObString &sql, stmt::StmtType stmt_type, bool for_update);
void end_nested_stmt_if_need(pl::ObPLExecCtx *pl_ctx, int &result); void end_nested_stmt_if_need(pl::ObPLExecCtx *pl_ctx, int &result);
private: private:
bool is_inited_; bool is_inited_;