[CP] [CP] issue<50775099>:forbid set global var when executing nested sql
This commit is contained in:
@ -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;
|
||||||
|
|||||||
@ -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)) {
|
||||||
|
|||||||
@ -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_;
|
||||||
|
|||||||
Reference in New Issue
Block a user