/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX SQL_OPT #include "sql/ob_sql_utils.h" #include "sql/ob_sql.h" #include #include #include "lib/string/ob_sql_string.h" #include "lib/timezone/ob_time_convert.h" #include "common/sql_mode/ob_sql_mode_utils.h" #include "share/ob_i_data_access_service.h" #include "share/stat/ob_stat_manager.h" #include "share/stat/ob_table_stat.h" #include "storage/ob_partition_service.h" #include "sql/parser/ob_parser.h" #include "sql/parser/parse_malloc.h" #include "sql/parser/parse_node.h" #include "sql/code_generator/ob_expr_generator_impl.h" #include "sql/code_generator/ob_code_generator_impl.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "sql/resolver/ob_resolver_utils.h" #include "sql/resolver/dml/ob_sql_hint.h" #include "sql/resolver/ob_stmt_type.h" #include "sql/resolver/expr/ob_raw_expr_precalc_analyzer.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_expr_func_part_hash.h" #include "sql/engine/expr/ob_expr_column_conv.h" #include "sql/rewrite/ob_query_range.h" #include "sql/session/ob_basic_session_info.h" #include "sql/plan_cache/ob_sql_parameterization.h" #include "sql/ob_select_stmt_printer.h" #include "sql/ob_insert_stmt_printer.h" #include "sql/ob_update_stmt_printer.h" #include "sql/ob_delete_stmt_printer.h" #include "sql/ob_merge_stmt_printer.h" #include "sql/executor/ob_task_executor_ctx.h" #include "sql/optimizer/ob_route_policy.h" #include "sql/rewrite/ob_transform_rule.h" #include "common/ob_smart_call.h" #include "observer/omt/ob_tenant_timezone_mgr.h" #include "share/schema/ob_schema_printer.h" #include "sql/resolver/expr/ob_raw_expr.h" using namespace oceanbase; using namespace oceanbase::sql; using namespace oceanbase::obmysql; using namespace oceanbase::common; using namespace oceanbase::share; using namespace oceanbase::share::schema; bool ObSQLUtils::is_trans_commit_need_disconnect_err(int err) { bool bool_ret = true; if (OB_SUCCESS == err || OB_TRANS_KILLED == err || OB_TRANS_CTX_NOT_EXIST == err || OB_TRANS_TIMEOUT == err || OB_TRANS_STMT_TIMEOUT == err || OB_TRANS_NEED_ROLLBACK == err || OB_TRANS_ROLLBACKED == err || OB_NOT_MASTER == err || OB_TRANS_IS_EXITING == err) { bool_ret = false; } return bool_ret; } void ObSQLUtils::check_if_need_disconnect_after_end_trans( const int end_trans_err, const bool is_rollback, const bool is_explicit, bool& is_need_disconnect) { is_need_disconnect = false; if (is_rollback) { // rollback if (OB_UNLIKELY(OB_SUCCESS != end_trans_err && is_explicit)) { is_need_disconnect = true; LOG_WARN("fail to rollback explicitly, disconnect", K(end_trans_err)); } else { is_need_disconnect = false; } } else { // commit if (OB_UNLIKELY(ObSQLUtils::is_trans_commit_need_disconnect_err(end_trans_err))) { is_need_disconnect = true; LOG_WARN("fail to commit, and error number is unexpected, disconnect", K(end_trans_err), K(lbt())); } else { is_need_disconnect = false; } } } int ObSQLUtils::md5(const ObString& stmt, char* sql_id, int32_t len) { const int32_t MD5_LENGTH = 16; int ret = OB_SUCCESS; if (sql_id == NULL || len < 32) { ret = OB_INVALID_ARGUMENT; SQL_PC_LOG(WARN, "invalid args", KP(sql_id), K(len)); } char md5_sum_buf[MD5_LENGTH]; ObString::obstr_size_t md5_sum_len = MD5_LENGTH; if (OB_SUCC(ret)) { unsigned char* res = MD5(reinterpret_cast(stmt.ptr()), stmt.length(), reinterpret_cast(md5_sum_buf)); if (OB_ISNULL(res)) { // MD5() in openssl always return an pointer not NULL, so we need not check return value. // Even so, we HAVE TO check it here. You know it. ret = OB_ERR_UNEXPECTED; LOG_WARN("md5 res null pointer", K(ret), K(res)); } else if (OB_FAIL(to_hex_cstr(md5_sum_buf, md5_sum_len, sql_id, len))) { LOG_WARN("transform to hex str error", K(ret)); } else { } // do nothing } return ret; } int ObSQLUtils::calc_partition_ids(const ObIArray& ranges, const ObSqlExpression& partition_func, const uint64_t part_num, ObIArray& partition_ids) { int ret = OB_SUCCESS; ObSEArray par_ids; // for keeping the perhaps duplicate partition ids ObNewRow calc_row; ObExprCtx expr_ctx; ObObj result; ObArenaAllocator allocator(common::ObModIds::OB_SQL_EXPR_CALC); expr_ctx.calc_buf_ = &allocator; int64_t N = ranges.count(); for (int64_t i = 0; OB_SUCC(ret) && i < N; ++i) { // calculate ObNewRange* range = ranges.at(i); if (OB_ISNULL(range)) { ret = OB_ERR_UNEXPECTED; SQL_EXE_LOG(WARN, "invalid argument", K(ret)); } else { calc_row.reset(); result.reset(); int64_t result_par_id = 0; // assuming all ranges are single-value calc_row.cells_ = const_cast(range->start_key_.get_obj_ptr()); calc_row.count_ = (range->start_key_.get_obj_cnt()); if (OB_FAIL(partition_func.calc(expr_ctx, calc_row, result))) { SQL_EXE_LOG(WARN, "fail to calc hash expr", K(ret), K(calc_row)); } else if (OB_FAIL(result.get_int(result_par_id))) { SQL_EXE_LOG(WARN, "fail to get int64 from result", K(ret), K(result)); } else if (OB_FAIL(par_ids.push_back(result_par_id % part_num))) { SQL_EXE_LOG(WARN, "fail to push back partition id into array", K(ret)); } } } if (OB_SUCC(ret)) { for (int64_t i = 0; OB_SUCC(ret) && i < par_ids.count(); ++i) { bool duplicated = false; for (int64_t j = 0; !duplicated && j < partition_ids.count(); ++j) { if (par_ids.at(i) == partition_ids.at(j)) { duplicated = true; } } if (!duplicated) { if (OB_FAIL(partition_ids.push_back(par_ids.at(i)))) { SQL_EXE_LOG(WARN, "fail to push back partition id into array", K(ret)); } } } } return ret; } int ObSQLUtils::get_phy_plan_type( ObIArray& part_location_set, const ObAddr& my_address, ObPhyPlanType& plan_type) { int ret = OB_SUCCESS; bool is_same = true; int64_t N = part_location_set.count(); if (0 == N) { plan_type = OB_PHY_PLAN_LOCAL; LOG_TRACE("no tables used, thus local plan"); } else { ObReplicaLocation replica_first; if (OB_FAIL(part_location_set.at(0).get_strong_leader(replica_first))) { SQL_EXE_LOG(WARN, "failed to get leader replica location", K(ret)); } else { SQL_EXE_LOG(DEBUG, "part_location_set first replica", K(ret), K(replica_first)); for (int64_t i = 1; OB_SUCC(ret) && true == is_same && i < N; ++i) { ObReplicaLocation replica_location; if (OB_FAIL(part_location_set.at(i).get_strong_leader(replica_location))) { SQL_EXE_LOG(WARN, "failed to get leader replica location", K(ret)); } else { is_same = is_same && (replica_location.server_ == replica_first.server_); SQL_EXE_LOG(DEBUG, "part_location_set replica", K(ret), K(i), K(replica_location)); } } if (OB_SUCC(ret)) { if (is_same) { if (my_address == replica_first.server_) { plan_type = OB_PHY_PLAN_LOCAL; } else { plan_type = OB_PHY_PLAN_REMOTE; } } else { plan_type = OB_PHY_PLAN_DISTRIBUTED; } } } } return ret; } int ObSQLUtils::has_local_leader_replica( const ObPartitionLocationIArray& part_array, const ObAddr& addr, ObPartitionKey& key, bool& has_local) { int ret = OB_SUCCESS; // get first local partition has_local = false; // init with firt partition key if (part_array.count() > 0) { if (OB_FAIL(part_array.at(0).get_partition_key(key))) { LOG_WARN("Get partition key error", "partition", part_array.at(0), K(ret)); } } for (int64_t i = 0; !has_local && OB_SUCCESS == ret && i < part_array.count(); i++) { ObReplicaLocation replica_leader; if (OB_FAIL(part_array.at(i).get_strong_leader(replica_leader))) { LOG_WARN("Get leader error", K(ret)); } else if (addr == replica_leader.server_) { // local partition if (OB_FAIL(part_array.at(i).get_partition_key(key))) { LOG_WARN("Get partition key error", "partition", part_array.at(i), K(ret)); } else { has_local = true; } } } return ret; } int ObSQLUtils::has_local_replica(const ObPhyPartitionLocationInfoIArray& part_loc_info_array, const common::ObAddr& addr, common::ObPartitionKey& key, bool& has_local) { int ret = OB_SUCCESS; has_local = false; // init with firt partition key if (part_loc_info_array.count() > 0) { if (OB_FAIL(part_loc_info_array.at(0).get_partition_location().get_partition_key(key))) { LOG_WARN("Get partition key error", "partition info", part_loc_info_array.at(0), K(ret)); } } for (int64_t i = 0; !has_local && OB_SUCC(ret) && i < part_loc_info_array.count(); ++i) { const ObOptPartLoc& part_loc = part_loc_info_array.at(i).get_partition_location(); const ObIArray& replica_loc_array = part_loc.get_replica_locations(); for (int64_t j = 0; !has_local && OB_SUCC(ret) && j < replica_loc_array.count(); ++j) { const ObReplicaLocation& replica_location = replica_loc_array.at(j); if (addr == replica_location.server_) { if (OB_FAIL(part_loc.get_partition_key(key))) { LOG_WARN("Get partition key error", K(part_loc), K(ret)); } else { has_local = true; } } } } if (OB_FAIL(ret)) { LOG_TRACE("[FIND LOCAL REPLICA] ret is failed", K(ret), K(key), K(addr), K(has_local)); } else if (has_local) { LOG_TRACE("[FIND LOCAL REPLICA] has local replica", K(key), K(addr)); } else { LOG_TRACE("[FIND LOCAL REPLICA] no local replica", K(addr)); } return ret; } int ObSQLUtils::find_all_local_replica(const ObPhyPartitionLocationInfoIArray& part_loc_info_array, const common::ObAddr& addr, common::ObIArray& keys) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < part_loc_info_array.count(); ++i) { const ObOptPartLoc& part_loc = part_loc_info_array.at(i).get_partition_location(); const ObIArray& replica_loc_array = part_loc.get_replica_locations(); ObPartitionKey temp_key; bool has_local = false; for (int64_t j = 0; OB_SUCC(ret) && !has_local && j < replica_loc_array.count(); j++) { const ObReplicaLocation& replica_location = replica_loc_array.at(j); if (addr == replica_location.server_) { if (OB_FAIL(part_loc.get_partition_key(temp_key))) { LOG_WARN("Get partition key error", K(part_loc), K(ret)); } else if (OB_FAIL(keys.push_back(temp_key))) { LOG_WARN("failed to push back temp key", K(ret)); } else { has_local = true; } } } } return ret; } int ObSQLUtils::replace_questionmarks(ParseNode* tree, const ParamStore& params) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("failed to check stack overflow", K(ret), K(is_stack_overflow)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else if (NULL != tree) { // replace ? with given params if (T_QUESTIONMARK == tree->type_) { const ObObj& param = params.at(tree->value_); switch (param.get_type()) { case ObIntType: tree->value_ = param.get_int(); tree->type_ = T_INT; break; case ObDateTimeType: tree->value_ = param.get_datetime(); tree->type_ = T_DATETIME; break; case ObTimestampType: tree->value_ = param.get_timestamp(); tree->type_ = T_TIMESTAMP; break; case ObDateType: tree->value_ = param.get_date(); tree->type_ = T_DATE; break; case ObTimeType: tree->value_ = param.get_time(); tree->type_ = T_TIME; break; case ObYearType: tree->value_ = param.get_year(); tree->type_ = T_YEAR; break; case ObVarcharType: tree->str_value_ = param.get_varchar().ptr(); tree->str_len_ = param.get_varchar().length(); tree->type_ = T_VARCHAR; break; case ObTinyIntType: tree->value_ = param.get_bool(); tree->type_ = T_BOOL; break; case ObNumberType: tree->str_value_ = param.get_number().format(); tree->type_ = T_NUMBER; break; default: LOG_WARN("never reach here", "type", param.get_type()); break; } } for (int32_t i = 0; OB_SUCC(ret) && i < tree->num_child_; ++i) { if (OB_ISNULL(tree->children_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid argument"); } else { ret = SMART_CALL(replace_questionmarks(tree->children_[i], params)); } } } return ret; } int ObSQLUtils::calc_const_or_calculable_expr(const stmt::StmtType stmt_type, ObSQLSessionInfo* session, const ObRawExpr* raw_expr, ObObj& result, const ParamStore* params, ObIAllocator& allocator) { int ret = OB_SUCCESS; ObRawExprFactory expr_factory(allocator); if (OB_ISNULL(raw_expr) || OB_ISNULL(params)) { ret = OB_INVALID_ARGUMENT; SQL_LOG(WARN, "Input arguments error", K(raw_expr), K(params), K(ret)); } else if (raw_expr->is_const_expr()) { bool need_check = false; if (OB_FAIL(calc_const_expr(raw_expr, params, result, need_check))) { SQL_LOG(WARN, "failed to calc const expr", K(ret)); } else { /*do nothing*/ } } else if (raw_expr->has_flag(IS_CALCULABLE_EXPR)) { if (OB_FAIL(calc_calculable_expr(stmt_type, session, raw_expr, result, &allocator, *params))) { SQL_LOG(WARN, "Get calculable expr value without addr to parition id error", K(ret)); } } else { ret = OB_INVALID_ARGUMENT; SQL_LOG(WARN, "Expr should be const_expr or calculable_expr", K(*raw_expr), K(ret)); } return ret; } int ObSQLUtils::calc_simple_expr_without_row(const stmt::StmtType stmt_type, ObSQLSessionInfo* session, const ObRawExpr* raw_expr, ObObj& result, const ParamStore* params, ObIAllocator& allocator) { int ret = OB_SUCCESS; ObRawExprFactory expr_factory(allocator); if (OB_ISNULL(raw_expr) || OB_ISNULL(params)) { ret = OB_INVALID_ARGUMENT; SQL_LOG(WARN, "Input arguments error", K(raw_expr), K(params), K(ret)); } else if (raw_expr->is_const_expr()) { bool need_check = false; if (OB_FAIL(calc_const_expr(raw_expr, params, result, need_check))) { SQL_LOG(WARN, "failed to calc const expr", KPC(raw_expr), K(ret)); } else { /*do nothing*/ } } else if (OB_FAIL(calc_const_expr(stmt_type, session, *raw_expr, result, allocator, *params))) { SQL_LOG(WARN, "Get const_expr value error", KPC(raw_expr), K(ret)); } return ret; } int ObSQLUtils::calc_raw_expr_without_row(ObExecContext& exec_ctx, const ObRawExpr* raw_expr, ObObj& result, const ParamStore* params, ObIAllocator& allocator) { int ret = OB_SUCCESS; bool is_overflow = false; if (OB_FAIL(check_stack_overflow(is_overflow))) { LOG_WARN("failed to check stack overflow", K(ret)); } else if (is_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recusive", K(ret)); } if (OB_FAIL(ret)) { // do nothing } else if (OB_ISNULL(raw_expr)) { ret = OB_INVALID_ARGUMENT; SQL_LOG(WARN, "Input arguments error", K(raw_expr), K(ret)); } else if (raw_expr->is_const_expr()) { bool need_check = false; if (OB_FAIL(calc_const_expr(raw_expr, params, result, need_check))) { SQL_LOG(WARN, "failed to calc const expr", K(ret)); } else { /*do nothing*/ } } else { ParamStore empty_params; if (OB_FAIL(calc_const_expr( stmt::T_NONE, exec_ctx, raw_expr, result, &allocator, NULL == params ? empty_params : *params))) { SQL_LOG(WARN, "Get calculable expr value without addr to parition id error", K(ret)); } else { /*do nothing*/ } } return ret; } int ObSQLUtils::calc_sql_expression_without_row(ObExecContext& exec_ctx, const ObISqlExpression& expr, ObObj& result) { int ret = OB_SUCCESS; if (OB_ISNULL(exec_ctx.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("physical plan context is NULL", K(ret)); } else if (OB_ISNULL(exec_ctx.get_my_session())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { ObExprCtx expr_ctx; ObNewRow empty_row; exec_ctx.get_physical_plan_ctx()->set_cur_time(ObTimeUtility::current_time()); // set the current time if (OB_FAIL(wrap_expr_ctx(stmt::T_NONE, exec_ctx, exec_ctx.get_allocator(), expr_ctx))) { LOG_WARN("Failed to wrap expr ctx", K(ret)); } else if (OB_FAIL(expr.calc(expr_ctx, empty_row, result))) { LOG_WARN("failed to calc expression", K(ret), K(expr)); } } return ret; } int ObSQLUtils::calc_const_expr( const ObRawExpr* expr, const ParamStore* params, common::ObObj& result, bool& need_check) { int ret = OB_SUCCESS; const ObConstRawExpr* const_expr = NULL; need_check = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(expr), K(ret)); } else if (OB_UNLIKELY(!expr->is_const_expr())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("not const expr", K(expr->get_expr_type()), K(ret)); } else if (FALSE_IT(const_expr = static_cast(expr))) { // do nothing } else if (T_QUESTIONMARK == const_expr->get_expr_type()) { if (OB_ISNULL(params)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(params), K(ret)); } else if (OB_FAIL(get_param_value(const_expr->get_value(), *params, result, need_check))) { LOG_WARN("get param value error", K(ret)); } else { /*do nothing*/ } } else { need_check = true; result = const_expr->get_value(); } return ret; } int ObSQLUtils::get_param_value( const common::ObObj& param, const ParamStore& params_array, ObObjParam& result, bool& need_check) { return get_param_value(param, params_array, result, need_check); } int ObSQLUtils::get_param_value( const common::ObObj& param, const ParamStore& params_array, common::ObObj& result, bool& need_check) { return get_param_value(param, params_array, result, need_check); } template int ObSQLUtils::get_param_value(const ObObj& param, const ParamStore& params_array, T& result, bool& need_check) { int ret = OB_SUCCESS; int64_t param_idx = -1; need_check = false; if (param.is_unknown()) { if (OB_FAIL(param.get_unknown(param_idx))) { SQL_LOG(WARN, "get question mark value failed", K(param), K(ret)); } else if (param_idx < 0 || param_idx >= params_array.count()) { ret = OB_ERR_ILLEGAL_INDEX; SQL_LOG(WARN, "Wrong index of question mark position", K(ret), K(param_idx)); } else { need_check = params_array.at(param_idx).need_to_check_bool_value(); result = params_array.at(param_idx); if (result.is_nop_value()) { ret = OB_ERR_NOP_VALUE; } } } return ret; } int ObSQLUtils::calc_calculable_expr(const stmt::StmtType stmt_type, ObSQLSessionInfo* session, const ObRawExpr* expr, ObObj& result, ObIAllocator* allocator, const ParamStore& params_array) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || OB_ISNULL(allocator)) { ret = OB_INVALID_ARGUMENT; SQL_LOG(WARN, "Invalid arguments", K(expr), K(allocator)); } else if (!expr->has_flag(IS_CALCULABLE_EXPR)) { ret = OB_INVALID_ARGUMENT; SQL_LOG(WARN, "expr should be calculabe expr", K(*expr), K(ret)); } else if (OB_FAIL(calc_const_expr(stmt_type, session, *expr, result, *allocator, params_array))) { SQL_LOG(WARN, "failed to calc const expr", K(*expr), K(ret)); } else { /*do nothing*/ } return ret; } int ObSQLUtils::calc_const_expr(const stmt::StmtType stmt_type, ObExecContext& exec_ctx, const ObRawExpr* expr, ObObj& result, ObIAllocator* allocator, const ParamStore& params_array) { int ret = OB_SUCCESS; if (OB_ISNULL(expr) || OB_ISNULL(allocator)) { ret = OB_INVALID_ARGUMENT; SQL_LOG(WARN, "Invalid arguments", K(expr), K(allocator)); } else if (OB_FAIL(calc_const_expr( stmt_type, exec_ctx.get_my_session(), *expr, result, *allocator, params_array, &exec_ctx))) { SQL_LOG(WARN, "failed to calc const expr", K(*expr), K(ret)); } else { /*do nothing*/ } return ret; } int ObSQLUtils::calc_const_expr(const stmt::StmtType stmt_type, ObSQLSessionInfo* session, const ObRawExpr& expr, ObObj& result, ObIAllocator& allocator, const ParamStore& params_array, ObExecContext* exec_ctx) { int ret = OB_SUCCESS; if (OB_ISNULL(session)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid null session", K(ret)); } else if (session->use_static_typing_engine()) { if (OB_FAIL(calc_const_expr(session, &expr, params_array, allocator, result))) { LOG_WARN("failed to calc const expr", K(ret)); } } else { ObPhysicalPlan phy_plan; ObPhysicalPlanCtx phy_plan_ctx(allocator); ObSqlExpression sql_expr(allocator, 0); SMART_VAR(ObExecContext, exec_ctx_dummy) { ObExecContext* exec_ctx_p = exec_ctx; ObExprCtx expr_ctx; RowDesc row_desc; ObNewRow empty_row; ObExprGeneratorImpl expr_generator(0, 0, NULL, row_desc); if (OB_ISNULL(exec_ctx_p)) { exec_ctx_dummy.set_my_session(session); exec_ctx_p = &exec_ctx_dummy; } phy_plan_ctx.set_cur_time(ObTimeUtility::current_time(), *session); if (OB_FAIL(wrap_expr_ctx(stmt_type, *exec_ctx_p, allocator, expr_ctx))) { LOG_WARN("fail to wrap expr ctx", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < params_array.count(); i++) { if (OB_FAIL(phy_plan_ctx.get_param_store_for_update().push_back(params_array.at(i)))) { SQL_LOG(WARN, "Add param to param_store failed", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(expr_generator.generate(const_cast(expr), sql_expr))) { SQL_LOG(WARN, "Generate post_expr error", K(ret)); } else { phy_plan.set_regexp_op_count(expr_generator.get_cur_regexp_op_count()); phy_plan.set_like_op_count(expr_generator.get_cur_like_op_count()); phy_plan_ctx.set_phy_plan(&phy_plan); expr_ctx.phy_plan_ctx_ = &phy_plan_ctx; if (OB_FAIL(sql_expr.calc(expr_ctx, empty_row, result))) { SQL_LOG(WARN, "Fail to calc expression", K(sql_expr), K(ret)); } } } } } return ret; } int ObSQLUtils::calc_const_expr(ObSQLSessionInfo* session, const ObRawExpr* expr, const ParamStore& params, ObIAllocator& allocator, common::ObObj& result) { int ret = OB_SUCCESS; OB_ASSERT(NULL != session); lib::ContextParam param; param.set_mem_attr(session->get_effective_tenant_id(), ObModIds::OB_SQL_EXECUTOR, ObCtxIds::DEFAULT_CTX_ID) .set_properties(lib::USE_TL_PAGE_OPTIONAL) .set_page_size(OB_MALLOC_BIG_BLOCK_SIZE); CREATE_WITH_TEMP_CONTEXT(param) { ObIAllocator& tmp_allocator = CURRENT_CONTEXT->get_arena_allocator(); ObPhysicalPlanCtx phy_plan_ctx(tmp_allocator); for (int i = 0; OB_SUCC(ret) && i < params.count(); i++) { if (OB_FAIL(phy_plan_ctx.get_param_store_for_update().push_back(params.at(i)))) { LOG_WARN("failed to push back element", K(ret)); } } // end for if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(phy_plan_ctx.init_datum_param_store())) { LOG_WARN("failed to init datum param store", K(ret)); } else { ObExecContext exec_ctx(tmp_allocator); exec_ctx.set_my_session(session); exec_ctx.set_physical_plan_ctx(&phy_plan_ctx); void* frame_buf = NULL; ObPreCalcExprFrameInfo* pre_calc_frame = NULL; ObStaticEngineExprCG expr_cg(tmp_allocator, &phy_plan_ctx.get_datum_param_store()); ObRawExpr* copied_expr = NULL; ObRawExprFactory expr_factory(tmp_allocator); int org_obj_cnt = phy_plan_ctx.get_param_store().count(); if (OB_FAIL(ObRawExprUtils::copy_expr(expr_factory, expr, copied_expr, COPY_REF_DEFAULT))) { LOG_WARN("failed to copy raw expr", K(ret)); } else if (OB_ISNULL(copied_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null expr", K(ret), K(copied_expr)); } else if (OB_ISNULL(frame_buf = tmp_allocator.alloc(sizeof(ObPreCalcExprFrameInfo)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else { pre_calc_frame = new (frame_buf) ObPreCalcExprFrameInfo(tmp_allocator); expr_cg.init_operator_cg_ctx(&exec_ctx); if (OB_FAIL(expr_cg.generate_calculable_expr(copied_expr, *pre_calc_frame))) { LOG_WARN("failed to generate calculable expr", K(ret)); // set current time before do pre calculation } else if (FALSE_IT(phy_plan_ctx.set_cur_time(ObTimeUtility::current_time(), *session))) { // do nothing } else if (OB_FAIL(ObCacheObject::pre_calculation(false, *pre_calc_frame, exec_ctx))) { LOG_WARN("failed to pre calculate", K(ret)); } else if (OB_UNLIKELY(org_obj_cnt + 1 != phy_plan_ctx.get_param_store().count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unpected param store", K(phy_plan_ctx.get_param_store()), K(org_obj_cnt)); } else if (OB_FAIL(deep_copy_obj(allocator, phy_plan_ctx.get_param_store().at(org_obj_cnt), result))) { LOG_WARN("failed to deep copy obj", K(ret)); } else { // do nothing } } } } return ret; } int ObSQLUtils::convert_calculable_expr_to_question_mark(ObDMLStmt& stmt, ObRawExpr*& expr, ObTransformerCtx& ctx) { int ret = OB_SUCCESS; int64_t old_idx = stmt.get_calculable_exprs().count(); int64_t old_pre_param_size = stmt.get_pre_param_size(); ObSEArray calculable_exprs; if (OB_ISNULL(ctx.exec_ctx_) || OB_ISNULL(ctx.phy_plan_) || OB_ISNULL(ctx.expr_factory_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL param", K(ret), K(ctx.exec_ctx_), K(ctx.phy_plan_)); } else { ObRawExprPrecalcAnalyzer pre_calc_analyzer(*ctx.expr_factory_, ctx.exec_ctx_->get_my_session()); if (OB_FAIL(pre_calc_analyzer.analyze_expr_tree(expr, stmt))) { LOG_WARN("analyze stmt all expr failed", K(ret)); } } // pre calculable if (OB_FAIL(ret)) { } else if (OB_FAIL(extract_calc_exprs(stmt, expr, old_idx, old_pre_param_size, calculable_exprs))) { LOG_WARN("failed to extract calc exprs", K(ret)); } else if (OB_FAIL(ObSql::calc_pre_calculable_exprs(calculable_exprs, *ctx.exec_ctx_, stmt, *ctx.phy_plan_))) { LOG_WARN("Failed to calc_pre_calculable_exprs", K(ret)); } return ret; } int ObSQLUtils::extract_calc_exprs(ObDMLStmt& stmt, ObRawExpr* expr, int64_t old_idx, int64_t old_pre_param_size, ObIArray& calc_exprs) { int ret = OB_SUCCESS; ObSEArray record_exprs; bool is_need_adjust = false; ObIArray& stmt_calc_exprs = stmt.get_calculable_exprs(); if (OB_UNLIKELY(old_idx > stmt_calc_exprs.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get invalid argument", K(ret), K(old_idx), K(stmt_calc_exprs.count())); } else if (1 == stmt_calc_exprs.count() - old_idx) { if (OB_FAIL(calc_exprs.push_back(stmt_calc_exprs.at(old_idx)))) { LOG_WARN("Failed to push back calculable_exprs", K(ret)); } else { /*do nothing*/ } } else if (stmt_calc_exprs.count() - old_idx > 1) { if (OB_FAIL(recursively_extract_calc_exprs( stmt_calc_exprs, expr, old_idx, old_pre_param_size, record_exprs, is_need_adjust, calc_exprs))) { LOG_WARN("failed to recursively extract calc exprs", K(ret)); } else if (is_need_adjust) { if (OB_UNLIKELY(calc_exprs.count() + old_idx != stmt_calc_exprs.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(stmt_calc_exprs.count()), K(calc_exprs.count() + old_idx)); } else { for (int64_t i = 0; i < calc_exprs.count(); ++i) { stmt.get_calculable_exprs().at(old_idx + i) = calc_exprs.at(i); } } } else { /*do nothing*/ } } else { /*do nothing*/ } return ret; } int ObSQLUtils::recursively_extract_calc_exprs(ObIArray& stmt_calc_exprs, ObRawExpr* expr, int64_t old_idx, int64_t old_pre_param_size, ObIArray& record_exprs, bool& is_need_adjust, ObIArray& calc_exprs) { int ret = OB_SUCCESS; bool is_stack_overflow = false; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(expr)); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { LOG_WARN("failed to check stack overflow", K(ret), K(is_stack_overflow)); } else if (is_stack_overflow) { ret = OB_SIZE_OVERFLOW; LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { ObRawExpr* param_expr = expr->get_param_expr(i); if (OB_ISNULL(param_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get unexpected null", K(ret), K(param_expr)); } else if (ObRawExprUtils::find_expr(record_exprs, param_expr)) { /*do nothing*/ } else if (T_QUESTIONMARK == param_expr->get_expr_type()) { int64_t idx = -1; ObObj& question_value = static_cast(param_expr)->get_value(); if (OB_FAIL(question_value.get_unknown(idx))) { LOG_WARN("failed to get unknown", K(ret)); } else if (-1 == idx || OB_UNLIKELY(idx - old_pre_param_size + old_idx >= stmt_calc_exprs.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get invalid argument", K(ret), K(idx - old_pre_param_size + old_idx), K(stmt_calc_exprs.count())); } else if (idx < old_pre_param_size) { /*do nothing*/ } else { ObHiddenColumnItem& hidden_col = stmt_calc_exprs.at(idx - old_pre_param_size + old_idx); int64_t old_calculable_exprs_size = calc_exprs.count(); if (OB_ISNULL(hidden_col.expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get unexpected null", K(ret), K(hidden_col.expr_)); } else if (OB_FAIL(SMART_CALL(recursively_extract_calc_exprs(stmt_calc_exprs, hidden_col.expr_, old_idx, old_pre_param_size, record_exprs, is_need_adjust, calc_exprs)))) { LOG_WARN("failed to recursively extract calc exprs", K(ret)); } else if (old_calculable_exprs_size != calc_exprs.count() || idx != calc_exprs.count() + old_pre_param_size) { hidden_col.hidden_idx_ = calc_exprs.count() + old_pre_param_size; ObObjParam val; val.set_unknown(hidden_col.hidden_idx_); val.set_param_meta(); const ObExprResType result_type = param_expr->get_result_type(); static_cast(param_expr)->set_value(val); param_expr->set_result_type(result_type); if (OB_FAIL(calc_exprs.push_back(hidden_col))) { LOG_WARN("failed to push back item", K(ret)); } else if (OB_FAIL(record_exprs.push_back(param_expr))) { LOG_WARN("failed to push back item", K(ret)); } else { is_need_adjust = true; } } else if (OB_FAIL(calc_exprs.push_back(hidden_col))) { LOG_WARN("failed to push back item", K(ret)); } else if (OB_FAIL(record_exprs.push_back(param_expr))) { LOG_WARN("failed to push back item", K(ret)); } else { /*do nothing*/ } } } else if (param_expr->has_flag(CNT_PARAM)) { if (OB_FAIL(SMART_CALL(recursively_extract_calc_exprs( stmt_calc_exprs, param_expr, old_idx, old_pre_param_size, record_exprs, is_need_adjust, calc_exprs)))) { LOG_WARN("failed to recursively extract calc exprs", K(ret)); } else { /*do nothing*/ } } else { /*do nothing*/ } } } return ret; } int ObSQLUtils::make_generated_expression_from_str(const common::ObString& expr_str, const share::schema::ObTableSchema& schema, const share::schema::ObColumnSchemaV2& gen_col, const common::ObIArray& col_ids, common::ObIAllocator& allocator, common::ObISqlExpression*& expression) { int ret = OB_SUCCESS; const bool make_column_expression = false; // return ObSqlExpression ObSQLSessionInfo default_session; uint64_t tenant_id = extract_tenant_id(schema.get_table_id()); const ObTenantSchema *tenant_schema = nullptr; ObSchemaGetterGuard guard; if (OB_FAIL(GCTX.schema_service_->get_tenant_schema_guard(tenant_id, guard))) { LOG_WARN("fail to get schema guard", K(ret)); } else if (OB_FAIL(default_session.init(0, 0, 0, &allocator))) { LOG_WARN("init empty session failed", K(ret)); } else if (OB_FAIL(guard.get_tenant_info(tenant_id, tenant_schema))) { LOG_WARN("fail to get tenant_schema", K(ret)); } else if (OB_FAIL(default_session.init_tenant(tenant_schema->get_tenant_name_str(), tenant_id))) { LOG_WARN("fail to init", K(ret)); } else if (OB_FAIL(default_session.load_all_sys_vars(guard))) { LOG_WARN("session load default system variable failed", K(ret)); } else if (OB_FAIL(make_generated_expression_from_str( expr_str, default_session, schema, gen_col, col_ids, allocator, expression, make_column_expression))) { LOG_WARN("make generated expression failed", K(ret), K(expr_str)); } return ret; } int ObSQLUtils::make_generated_expression_from_str(const common::ObString& expr_str, ObSQLSessionInfo& session, const share::schema::ObTableSchema& schema, const share::schema::ObColumnSchemaV2& gen_col, const common::ObIArray& col_ids, common::ObIAllocator& allocator, common::ObISqlExpression*& expression, const bool make_column_expression) { int ret = OB_SUCCESS; ObRawExprFactory expr_factory(allocator); ObRawExpr* expr = NULL; RowDesc row_desc; ObArray columns; if (OB_FAIL(ObRawExprUtils::build_generated_column_expr(expr_str, expr_factory, session, expr, columns))) { LOG_WARN("get generated column expr failed", K(ret)); } else if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is null"); } else if (OB_FAIL(row_desc.init())) { LOG_WARN("Failed to init row desc", K(ret)); } else { // create row_desc for (int64_t i = 0; OB_SUCC(ret) && i < col_ids.count(); ++i) { ObColumnRefRawExpr* col_ref = NULL; const ObColumnSchemaV2* col_schema = NULL; if (OB_ISNULL(col_schema = schema.get_column_schema(col_ids.at(i).col_id_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column schema failed", K_(col_ids.at(i).col_id)); } else if (OB_FAIL(ObRawExprUtils::build_column_expr(expr_factory, *col_schema, col_ref))) { LOG_WARN("build column expr failed", K(ret)); } else if (OB_FAIL(row_desc.add_column(col_ref))) { LOG_WARN("add column to row desc failed", K(ret)); } else { /*do nothing*/ } for (int64_t j = 0; OB_SUCC(ret) && j < columns.count(); ++j) { ObQualifiedName& q_name = columns.at(j); if (!q_name.database_name_.empty() || !q_name.tbl_name_.empty()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is not based on single table", K(q_name)); } else if (ObCharset::case_insensitive_equal(q_name.col_name_, col_schema->get_column_name_str())) { if (OB_FAIL(ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, col_ref))) { LOG_WARN("replace reference column failed", K(ret)); } } else { /*do nothing*/ } } } if (OB_SUCC(ret)) { if (OB_FAIL(ObRawExprUtils::build_pad_expr_recursively(expr_factory, session, schema, gen_col, expr))) { LOG_WARN("add pad expr failed", K(ret)); } else if (OB_FAIL(expr->formalize(&session))) { LOG_WARN("formalize expression failed", K(ret)); } } if (OB_SUCC(ret)) { ObExprResType dest_type; dest_type.set_meta(gen_col.get_meta_type()); dest_type.set_accuracy(gen_col.get_accuracy()); if (ObRawExprUtils::need_column_conv(dest_type, *expr)) { if (OB_FAIL(ObRawExprUtils::build_column_conv_expr(expr_factory, &gen_col, expr, &session))) { LOG_WARN("create column convert expr failed", K(ret)); } } } if (OB_SUCC(ret)) { ObSqlExpressionFactory sql_expression_factory(allocator); ObExprOperatorFactory expr_op_factory(allocator); ObExprGeneratorImpl expr_gen(expr_op_factory, 0, 0, NULL, row_desc); ObSqlExpression* sql_expr = NULL; ObColumnExpression* col_expr = NULL; if (!make_column_expression) { if (OB_FAIL(sql_expression_factory.alloc(sql_expr))) { LOG_WARN("alloc sql expression failed", K(ret)); } } else { if (OB_FAIL(sql_expression_factory.alloc(col_expr))) { LOG_WARN("alloc column expression failed", K(ret)); } else { sql_expr = col_expr; } } if (OB_FAIL(ret)) { } else if (OB_UNLIKELY(NULL == sql_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Failed to alloc sql expression", K(ret)); } else if (OB_FAIL(expr_gen.generate(*expr, *sql_expr))) { LOG_WARN("fail to fill sql expression", K(ret)); } else { expression = sql_expr; } } } return ret; } int ObSQLUtils::make_default_expr_context(uint64_t tenant_id, ObIAllocator &allocator, ObExprCtx &expr_ctx) { int ret = OB_SUCCESS; ObSchemaGetterGuard guard; const ObTenantSchema *tenant_schema = nullptr; ObSQLSessionInfo *default_session = static_cast(allocator.alloc(sizeof(ObSQLSessionInfo))); if (OB_ISNULL(default_session)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret)); } else if (OB_FAIL(GCTX.schema_service_->get_tenant_schema_guard(tenant_id, guard))) { LOG_WARN("fail to get schema guard", K(ret)); } else { default_session = new (default_session) ObSQLSessionInfo(); if (OB_FAIL(default_session->init(0, 0, 0, &allocator))) { LOG_WARN("init default session failed", K(ret)); } else if (OB_FAIL(guard.get_tenant_info(tenant_id, tenant_schema))) { LOG_WARN("fail to get tenant_schema", K(ret)); } else if (OB_FAIL(default_session->init_tenant(tenant_schema->get_tenant_name_str(), tenant_id))) { LOG_WARN("fail to init", K(ret)); } else if (OB_FAIL(default_session->load_all_sys_vars(guard))) { LOG_WARN("load default system variable to session failed", K(ret)); } else { expr_ctx.my_session_ = default_session; } } if (OB_SUCC(ret)) { ObPhysicalPlanCtx* phy_plan_ctx = static_cast(allocator.alloc(sizeof(ObPhysicalPlanCtx))); if (OB_ISNULL(phy_plan_ctx)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret)); } else { phy_plan_ctx = new (phy_plan_ctx) ObPhysicalPlanCtx(allocator); expr_ctx.phy_plan_ctx_ = phy_plan_ctx; } } if (OB_SUCC(ret)) { ObPhysicalPlan* phy_plan = static_cast(allocator.alloc(sizeof(ObPhysicalPlan))); if (OB_ISNULL(phy_plan)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret)); } else { phy_plan = new (phy_plan) ObPhysicalPlan(); expr_ctx.phy_plan_ctx_->set_phy_plan(phy_plan); } } if (OB_SUCC(ret)) { ObExecContext* exec_ctx = static_cast(allocator.alloc(sizeof(ObExecContext))); if (OB_ISNULL(exec_ctx)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret)); } else { exec_ctx = new (exec_ctx) ObExecContext(); exec_ctx->set_my_session(default_session); expr_ctx.exec_ctx_ = exec_ctx; } } if (OB_SUCC(ret)) { expr_ctx.calc_buf_ = &allocator; } if (OB_SUCC(ret)) { if (OB_FAIL(wrap_column_convert_ctx(expr_ctx, expr_ctx.column_conv_ctx_))) { LOG_WARN("wrap column convert ctx failed", K(ret)); } } return ret; } void ObSQLUtils::destruct_default_expr_context(ObExprCtx& expr_ctx) { if (NULL != expr_ctx.my_session_) { expr_ctx.my_session_->~ObSQLSessionInfo(); expr_ctx.my_session_ = NULL; } if (NULL != expr_ctx.phy_plan_ctx_ && NULL != expr_ctx.phy_plan_ctx_->get_phy_plan()) { expr_ctx.phy_plan_ctx_->get_phy_plan()->~ObPhysicalPlan(); expr_ctx.phy_plan_ctx_->set_phy_plan(NULL); } if (NULL != expr_ctx.phy_plan_ctx_) { expr_ctx.phy_plan_ctx_->~ObPhysicalPlanCtx(); expr_ctx.phy_plan_ctx_ = NULL; } if (NULL != expr_ctx.exec_ctx_) { expr_ctx.exec_ctx_->~ObExecContext(); expr_ctx.exec_ctx_ = NULL; } } int ObSQLUtils::calc_sql_expression(const ObISqlExpression* expr, const share::schema::ObTableSchema& schema, const ObIArray& col_ids, const ObNewRow& row, ObIAllocator& allocator, ObExprCtx& expr_ctx, ObObj& result) { UNUSED(schema); UNUSED(allocator); UNUSED(col_ids); int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Expr to calc is NULL", K(expr), K(ret)); } else if (col_ids.count() != row.count_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("cells count in row is not equal to col_ids", K(col_ids), K(row.count_), K(ret)); } else { ObNewRow pad_row; bool need_pad = false; /* if (is_pad_char_to_full_length(expr_ctx.my_session_->get_sql_mode())) { ObSEArray whitespace_length; for (int64_t i = 0; OB_SUCC(ret) && i < col_ids.count(); ++i) { if (col_ids.at(i).col_type_.is_fixed_len_char_type()) { const ObColumnSchemaV2* col_schema = NULL; if (OB_ISNULL(col_schema = schema.get_column_schema(col_ids.at(i).col_id_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get column schema failed", K_(col_ids.at(i).col_id)); } else { const ObAccuracy accuracy = col_schema->get_accuracy(); int32_t cell_strlen = 0; // byte or char length if (OB_FAIL(row.cells_[i].get_char_length(accuracy, cell_strlen, share::is_oracle_mode()))) { STORAGE_LOG(WARN, "Fail to get char length, ", K(ret)); } else { need_pad = need_pad ? true : cell_strlen < col_schema->get_data_length(); if (OB_FAIL(whitespace_length.push_back(col_schema->get_data_length() - cell_strlen))) { LOG_WARN("push back error", K(whitespace_length), K(ret)); } } } } else { if (OB_FAIL(whitespace_length.push_back(0))) { LOG_WARN("push back error", K(whitespace_length), K(ret)); } } } if (OB_SUCC(ret) && need_pad) { if (row.count_ != whitespace_length.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cells count in row is not equal to pad_length", K(row), K(whitespace_length), K(ret)); } else { pad_row.cells_ = static_cast(allocator.alloc(sizeof(common::ObObj) * row.count_)); if (OB_ISNULL(pad_row.cells_)) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("no memory", K(sizeof(common::ObObj)), K(row.count_), K(ret)); } else { pad_row.cells_ = new (pad_row.cells_) common::ObObj[row.count_](); for (int64_t i = 0; OB_SUCC(ret) && i < row.count_; ++i) { if (whitespace_length.at(i) > 0) { ObString res_string; if (OB_FAIL(ObCharset::whitespace_padding(allocator, row.cells_[i].get_collation_type(), row.cells_[i].get_string(), whitespace_length.at(i), res_string))) { LOG_WARN("whitespace_padding failed", K(ret), K(whitespace_length.at(i))); } else { pad_row.cells_[i].set_string(row.cells_[i].get_type(), res_string); } } else { pad_row.cells_[i] = row.cells_[i]; } } } } } } */ if (OB_SUCC(ret)) { if (OB_FAIL(expr->calc(expr_ctx, need_pad ? pad_row : row, result))) { LOG_WARN("Fail to calc value", K(ret), K(*expr), K(row), K(need_pad), K(pad_row)); } } } return ret; } int64_t ObSQLUtils::get_usec() { struct timeval time_val; if (0 != gettimeofday(&time_val, NULL)) { // success: return 0, failed: return -1 LOG_WARN("fail to get time of day"); } return time_val.tv_sec * 1000000 + time_val.tv_usec; } int ObSQLUtils::check_and_convert_db_name(const ObCollationType cs_type, const bool perserve_lettercase, ObString& name) { int ret = OB_SUCCESS; UNUSED(cs_type); ObString origin_name = name; int64_t name_len = name.length(); const char* name_str = name.ptr(); int32_t max_database_name_length = GET_MIN_CLUSTER_VERSION() < CLUSTER_CURRENT_VERSION ? OB_MAX_DATABASE_NAME_LENGTH - 1 : OB_MAX_DATABASE_NAME_LENGTH; if (0 == name_len || name_len > (max_database_name_length * OB_MAX_CHAR_LEN)) { ret = OB_WRONG_DB_NAME; LOG_USER_ERROR(OB_WRONG_DB_NAME, static_cast(name_len), name_str); LOG_WARN("incorrect database name", K(name), K(ret)); } else { bool check_for_path_chars = check_mysql50_prefix(name); if (check_for_path_chars) { name_str += OB_MYSQL50_TABLE_NAME_PREFIX_LENGTH; name_len -= OB_MYSQL50_TABLE_NAME_PREFIX_LENGTH; } ObString last_name(name_len, name_str); if (!perserve_lettercase) { ObCharset::casedn(CS_TYPE_UTF8MB4_BIN, last_name); } if (OB_ERR_WRONG_IDENT_NAME == (ret = check_ident_name(cs_type, last_name, check_for_path_chars, max_database_name_length))) { ret = OB_WRONG_DB_NAME; LOG_USER_ERROR(OB_WRONG_DB_NAME, static_cast(origin_name.length()), origin_name.ptr()); LOG_WARN("Incorrect database name", K(origin_name), K(ret)); } else if (OB_ERR_TOO_LONG_IDENT == ret) { LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, static_cast(origin_name.length()), origin_name.ptr()); LOG_WARN("database name is too long", K(origin_name), K(ret)); } else if (OB_FAIL(ret)) { LOG_WARN("fail to check ident name", K(origin_name), K(ret)); } else { name = last_name; } } return ret; } int ObSQLUtils::cvt_db_name_to_org( share::schema::ObSchemaGetterGuard& schema_guard, const ObSQLSessionInfo* session, common::ObString& name) { int ret = OB_SUCCESS; if (lib::is_mysql_mode() && session != NULL && !session->is_inner()) { ObNameCaseMode case_mode = OB_NAME_CASE_INVALID; if (OB_FAIL(session->get_name_case_mode(case_mode))) { LOG_WARN("fail to get name case mode", K(ret)); } else if (case_mode == OB_ORIGIN_AND_INSENSITIVE) { const ObDatabaseSchema* db_schema = NULL; if (OB_FAIL(schema_guard.get_database_schema(session->get_effective_tenant_id(), name, db_schema))) { LOG_WARN("fail to get database schema", K(name), K(ret)); } else if (db_schema != NULL) { name = db_schema->get_database_name(); } } } return ret; } int ObSQLUtils::check_and_convert_table_name(const ObCollationType cs_type, const bool perserve_lettercase, ObString& name, const stmt::StmtType stmt_type, const bool is_index_table) { UNUSED(cs_type); int ret = OB_SUCCESS; int64_t name_len = name.length(); const char* name_str = name.ptr(); const int64_t max_user_table_name_length = share::is_oracle_mode() ? OB_MAX_USER_TABLE_NAME_LENGTH_ORACLE : OB_MAX_USER_TABLE_NAME_LENGTH_MYSQL; const int64_t max_index_name_prefix_len = 30; if (0 == name_len || (!is_index_table && (name_len > (max_user_table_name_length * OB_MAX_CHAR_LEN))) || (is_index_table && (name_len > (max_user_table_name_length * OB_MAX_CHAR_LEN + max_index_name_prefix_len))) || OB_ISNULL(name_str)) { ret = OB_WRONG_TABLE_NAME; LOG_USER_ERROR(OB_WRONG_TABLE_NAME, static_cast(name_len), name_str); LOG_WARN("incorrect table name", K(name), K(ret)); } else { char origin_name[OB_MAX_USER_TABLE_NAME_LENGTH_ORACLE * OB_MAX_CHAR_LEN + 1] = {'\0'}; MEMCPY(origin_name, name_str, name_len); if (!perserve_lettercase) { ObCharset::casedn(CS_TYPE_UTF8MB4_GENERAL_CI, name); } bool check_for_path_chars = false; int64_t max_ident_len = max_user_table_name_length; if (stmt::T_SELECT == stmt_type && is_index_table) { max_ident_len = OB_MAX_TABLE_NAME_LENGTH; } if (OB_ERR_WRONG_IDENT_NAME == (ret = check_ident_name(CS_TYPE_UTF8MB4_GENERAL_CI, name, check_for_path_chars, max_ident_len))) { ret = OB_WRONG_TABLE_NAME; LOG_USER_ERROR(OB_WRONG_TABLE_NAME, (int)strlen(origin_name), origin_name); LOG_WARN("Incorrect table name", K(origin_name), K(ret)); } else if (OB_ERR_TOO_LONG_IDENT == ret) { LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, (int)strlen(origin_name), origin_name); LOG_WARN("table name is too long", K(origin_name), K(max_ident_len), K(ret)); } else if (OB_FAIL(ret)) { LOG_WARN("fail to check ident name", K(origin_name), K(ret)); } } return ret; } int ObSQLUtils::check_index_name(const ObCollationType cs_type, ObString& name) { UNUSED(cs_type); int ret = OB_SUCCESS; int64_t name_len = name.length(); const char* name_str = name.ptr(); const int64_t max_user_table_name_length = share::is_oracle_mode() ? OB_MAX_USER_TABLE_NAME_LENGTH_ORACLE : OB_MAX_USER_TABLE_NAME_LENGTH_MYSQL; if (name_len > (max_user_table_name_length * OB_MAX_CHAR_LEN)) { ret = OB_ERR_TOO_LONG_IDENT; LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, static_cast(name_len), name_str); LOG_WARN("index name is too long", K(name), K(ret)); } else if (0 == name_len) { if (share::is_oracle_mode()) { ret = OB_ERR_ZERO_LENGTH_IDENTIFIER; LOG_WARN("index name is empty", K(ret)); } else { ret = OB_WRONG_NAME_FOR_INDEX; LOG_WARN("index name is empty", K(ret)); LOG_USER_ERROR(OB_WRONG_NAME_FOR_INDEX, static_cast(name_len), name_str); } } else { bool check_for_path_chars = false; if (OB_ERR_WRONG_IDENT_NAME == (ret = check_ident_name(CS_TYPE_UTF8MB4_GENERAL_CI, name, check_for_path_chars, max_user_table_name_length))) { ret = OB_WRONG_NAME_FOR_INDEX; LOG_USER_ERROR(OB_WRONG_NAME_FOR_INDEX, name.length(), name.ptr()); LOG_WARN("Incorrect index name", K(name), K(ret)); } else if (OB_ERR_TOO_LONG_IDENT == ret) { LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, name.length(), name.ptr()); LOG_WARN("index name is too long", K(name), K(ret)); } else if (OB_FAIL(ret)) { LOG_WARN("fail to check ident name", K(name), K(ret)); } } return ret; } int ObSQLUtils::check_column_name(const ObCollationType cs_type, ObString& name) { UNUSED(cs_type); int ret = OB_SUCCESS; bool last_char_is_space = false; const char* end = name.ptr() + name.length(); const char* name_str = name.ptr(); size_t name_len = 0; // char semantics for MySQL mode, and byte semantics for Oracle mode size_t byte_length = 0; int is_mb_char = 0; while (OB_SUCCESS == ret && name_str != end) { last_char_is_space = ObCharset::is_space(CS_TYPE_UTF8MB4_GENERAL_CI, *name_str); if (ObCharset::usemb(CS_TYPE_UTF8MB4_GENERAL_CI)) { is_mb_char = ObCharset::is_mbchar(CS_TYPE_UTF8MB4_GENERAL_CI, name_str, end); if (is_mb_char) { byte_length = ObCharset::charpos(CS_TYPE_UTF8MB4_GENERAL_CI, name_str, end - name_str, 1); name_str += byte_length; if (share::is_mysql_mode()) { name_len++; } else { name_len += byte_length; } continue; } } last_char_is_space = (*name_str == ' '); if ('\377' == *name_str) { ret = OB_WRONG_COLUMN_NAME; } else { name_str++; name_len++; } } if (OB_SUCC(ret)) { if (last_char_is_space) { ret = OB_WRONG_COLUMN_NAME; LOG_USER_ERROR(OB_WRONG_COLUMN_NAME, name.length(), name.ptr()); LOG_WARN("incorrect column name", K(name), K(ret)); } else if (name_len > static_cast(OB_MAX_COLUMN_NAME_LENGTH)) { ret = OB_ERR_TOO_LONG_IDENT; LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, name.length(), name.ptr()); LOG_WARN("column name is too long", K(ret), K(name), K(name_len)); } } return ret; } int ObSQLUtils::check_and_copy_column_alias_name( const ObCollationType cs_type, const bool is_auto_gen, ObIAllocator* allocator, ObString& name) { int ret = OB_SUCCESS; UNUSED(cs_type); ObString origin_name = name; if (NULL == allocator) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid allocator is NULL", K(ret)); } else if (OB_FAIL(make_field_name( name.ptr(), static_cast(name.length()), CS_TYPE_UTF8MB4_GENERAL_CI, allocator, name))) { LOG_WARN("fail to copy column alias name", K(origin_name), K(ret)); } else { if (name.length() < origin_name.length() && !is_auto_gen) { if (0 == name.length()) { LOG_USER_WARN(OB_ERR_NAME_BECOMES_EMPTY, origin_name.length(), origin_name.ptr()); } else { LOG_USER_WARN(OB_ERR_REMOVED_SPACES, origin_name.length(), origin_name.ptr()); } } } return ret; } int ObSQLUtils::check_ident_name( const ObCollationType cs_type, ObString& name, const bool check_for_path_char, const int64_t max_ident_len) { int ret = OB_SUCCESS; UNUSED(cs_type); bool last_char_is_space = false; const char* end = name.ptr() + name.length(); const char* name_str = name.ptr(); size_t name_len = 0; // char semantics for MySQL mode, and byte semantics for Oracle mode size_t byte_length = 0; int is_mb_char = 0; while (OB_SUCCESS == ret && NULL != name_str && name_str != end) { last_char_is_space = ObCharset::is_space(CS_TYPE_UTF8MB4_GENERAL_CI, *name_str); if (ObCharset::usemb(CS_TYPE_UTF8MB4_GENERAL_CI)) { is_mb_char = ObCharset::is_mbchar(CS_TYPE_UTF8MB4_GENERAL_CI, name_str, end); if (is_mb_char) { byte_length = ObCharset::charpos(CS_TYPE_UTF8MB4_GENERAL_CI, name_str, end - name_str, 1); name_str += byte_length; if (share::is_mysql_mode()) { name_len++; } else { name_len += byte_length; } continue; } } if (check_for_path_char && ('/' == *name_str || '\\' == *name_str || '~' == *name_str || '.' == *name_str)) { ret = OB_ERR_WRONG_IDENT_NAME; LOG_WARN("Incorrect database name", K(name), K(ret)); } else { name_str++; name_len++; } } if (OB_SUCC(ret)) { if (last_char_is_space) { ret = OB_ERR_WRONG_IDENT_NAME; LOG_WARN("incorrect ident name", K(name), K(ret)); } else if (name_len > static_cast(max_ident_len)) { ret = OB_ERR_TOO_LONG_IDENT; LOG_WARN("ident name is too long", K(ret), K(name), K(name.length()), K(name_len)); } } return ret; } bool ObSQLUtils::check_mysql50_prefix(ObString& db_name) { bool ret = false; const char* str = db_name.ptr(); int64_t len = db_name.length(); if (NULL == str || len < OB_MYSQL50_TABLE_NAME_PREFIX_LENGTH) { // do nothing } else { ret = !STRNCMP(str, OB_MYSQL50_TABLE_NAME_PREFIX, OB_MYSQL50_TABLE_NAME_PREFIX_LENGTH); } return ret; } bool ObSQLUtils::cause_implicit_commit(ParseResult& result) { bool ret = false; if (NULL != result.result_tree_ && NULL != result.result_tree_->children_ && NULL != result.result_tree_->children_[0]) { ParseNode* root = result.result_tree_->children_[0]; ObItemType type = root->type_; if (T_SET_PASSWORD == type || T_DROP_USER == type || T_CREATE_USER == type || T_LOCK_USER == type || T_REVOKE == type || T_REVOKE_ALL == type || T_RENAME_USER == type || T_GRANT == type || T_CREATE_TABLE == type || T_ALTER_DATABASE == type || T_DROP_DATABASE == type || T_CREATE_TENANT == type || T_CREATE_VIEW == type || T_DROP_TABLE == type || T_DROP_INDEX == type || T_CREATE_DATABASE == type || T_MODIFY_TENANT == type || T_CREATE_INDEX == type || T_DROP_TENANT == type) { ret = true; } } return ret; } bool ObSQLUtils::is_end_trans_stmt(const ParseResult& result) { bool bret = false; if (NULL != result.result_tree_ && NULL != result.result_tree_->children_ && NULL != result.result_tree_->children_[0]) { bret = (T_COMMIT == result.result_tree_->children_[0]->type_ || T_ROLLBACK == result.result_tree_->children_[0]->type_) ? true : false; } return bret; } bool ObSQLUtils::is_commit_stmt(const ParseResult& result) { bool bret = false; if (NULL != result.result_tree_ && NULL != result.result_tree_->children_ && NULL != result.result_tree_->children_[0]) { bret = T_COMMIT == result.result_tree_->children_[0]->type_ ? true : false; } return bret; } bool ObSQLUtils::is_modify_tenant_stmt(ParseResult& result) { ObItemType type = T_INVALID; if (NULL != result.result_tree_ && NULL != result.result_tree_->children_ && NULL != result.result_tree_->children_[0]) { type = result.result_tree_->children_[0]->type_; } return type == T_MODIFY_TENANT; } bool ObSQLUtils::is_mysql_ps_not_support_stmt(const ParseResult& result) { bool ret = false; if (NULL != result.result_tree_ && NULL != result.result_tree_->children_ && NULL != result.result_tree_->children_[0]) { ParseNode* root = result.result_tree_->children_[0]; ObItemType type = root->type_; switch (type) { case T_SP_CREATE: case T_SP_DROP: { ret = true; break; } default: { ret = false; } } } return ret; } bool ObSQLUtils::is_readonly_stmt(ParseResult& result) { bool ret = false; if (NULL != result.result_tree_ && NULL != result.result_tree_->children_ && NULL != result.result_tree_->children_[0]) { ParseNode* root = result.result_tree_->children_[0]; ObItemType type = root->type_; if (T_SELECT == type && NULL == root->children_[PARSE_SELECT_FOR_UPD]) { ret = true; } else if (T_EXPLAIN == type && NULL != root->children_[1] && root->children_[1]->type_ == T_SELECT && NULL == root->children_[1]->children_[PARSE_SELECT_FOR_UPD]) { ret = true; } else if (T_SHOW_COLUMNS == type || T_SHOW_TABLES == type || T_SHOW_DATABASES == type || T_SHOW_TABLE_STATUS == type || T_SHOW_SERVER_STATUS == type || T_SHOW_VARIABLES == type || T_SHOW_SCHEMA == type || T_SHOW_CREATE_DATABASE == type || T_SHOW_CREATE_TABLE == type || T_SHOW_CREATE_VIEW == type || T_SHOW_WARNINGS == type || T_SHOW_ERRORS == type || T_SHOW_GRANTS == type || T_SHOW_CHARSET == type || T_SHOW_COLLATION == type || T_SHOW_PARAMETERS == type || T_SHOW_INDEXES == type || T_SHOW_PROCESSLIST == type || T_SHOW_TABLEGROUPS == type || T_USE_DATABASE == type || T_TRANSACTION == type || T_BEGIN == type || T_COMMIT == type || T_ROLLBACK == type || T_VARIABLE_SET == type || T_SHOW_RECYCLEBIN == type || T_SHOW_TENANT == type || T_SHOW_RESTORE_PREVIEW == type) { ret = true; } } return ret; } int ObSQLUtils::make_field_name( const char* src, const int64_t len, const ObCollationType cs_type, ObIAllocator* allocator, ObString& name) { int ret = OB_SUCCESS; if (len < 0 || OB_ISNULL(allocator)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(len), K(allocator), K(ret)); } else if (NULL == src || 0 == len) { name.assign_ptr(src, static_cast(len)); } else { int64_t new_length = len; const char* new_start = src; while (new_length && !ObCharset::is_graph(cs_type, *new_start)) { new_start++; new_length--; } int64_t final_len = min(new_length, OB_MAX_ALIAS_NAME_LENGTH); if (new_length == len) { name.assign_ptr(src, static_cast(final_len)); } else { char* buf = reinterpret_cast(allocator->alloc(final_len + 1)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("failed to allocate memory", K(ret)); } else { MEMCPY(buf, new_start, final_len); buf[final_len] = '\0'; name.assign_ptr(buf, static_cast(final_len)); } } } return ret; } int ObSQLUtils::set_compatible_cast_mode(const ObSQLSessionInfo* session, ObCastMode& cast_mode) { int ret = OB_SUCCESS; if (OB_ISNULL(session)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument in set_compatible_cast_mode ", K(session), K(ret), K(cast_mode), K(lbt())); } else if (is_oracle_mode()) { cast_mode &= ~CM_WARN_ON_FAIL; cast_mode |= CM_ORACLE_MODE; } else { cast_mode &= ~CM_ORACLE_MODE; } return ret; } int ObSQLUtils::get_default_cast_mode( const stmt::StmtType& stmt_type, const ObSQLSessionInfo* session, ObCastMode& cast_mode) { int ret = OB_SUCCESS; cast_mode = CM_NONE; if (OB_ISNULL(session)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(session), K(ret)); } else if (is_oracle_mode() && stmt::T_EXPLAIN != stmt_type) { cast_mode = CM_ORACLE_MODE; } else if (stmt::T_SELECT == stmt_type || stmt::T_EXPLAIN == stmt_type || (!is_strict_mode(session->get_sql_mode())) || session->is_ignore_stmt()) { cast_mode = CM_WARN_ON_FAIL; } return ret; } void ObSQLUtils::set_insert_update_scope(ObCastMode& cast_mode) { cast_mode = cast_mode | CM_INSERT_UPDATE_SCOPE; } bool ObSQLUtils::is_insert_update_scope(ObCastMode& cast_mode) { return (cast_mode & CM_INSERT_UPDATE_SCOPE); } int ObSQLUtils::get_default_cast_mode( const ObPhysicalPlan* plan, const ObSQLSessionInfo* session, ObCastMode& cast_mode) { int ret = OB_SUCCESS; if (OB_ISNULL(plan)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(plan), K(ret)); } else if (OB_FAIL(get_default_cast_mode(plan->get_stmt_type(), session, cast_mode))) { LOG_WARN("fail to get default cast mode", K(ret)); } return ret; } int ObSQLUtils::get_default_cast_mode(const ObSQLSessionInfo* session, ObCastMode& cast_mode) { int ret = OB_SUCCESS; cast_mode = CM_NONE; if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan or session is NULL", K(ret)); } else if (is_oracle_mode()) { cast_mode = CM_ORACLE_MODE; } else if (!is_strict_mode(session->get_sql_mode())) { cast_mode = CM_WARN_ON_FAIL; } return ret; } int ObSQLUtils::get_default_cast_mode( const bool is_explicit_cast, const uint32_t result_flag, const ObSQLSessionInfo* session, ObCastMode& cast_mode) { int ret = OB_SUCCESS; cast_mode = CM_NONE; if (OB_ISNULL(session)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("session is NULL", K(ret), KP(session)); } else if (OB_FAIL(ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode))) { LOG_WARN("ObSqlUtils::get_default_cast_mode failed", K(ret)); } else { if (is_explicit_cast) { cast_mode |= CM_EXPLICIT_CAST; } else { cast_mode &= ~CM_EXPLICIT_CAST; } if (result_flag & OB_MYSQL_ZEROFILL_FLAG) { cast_mode |= CM_ZERO_FILL; } if (!is_oracle_mode() && is_strict_mode(session->get_sql_mode())) { cast_mode |= CM_NONE; cast_mode |= CM_STRICT_MODE; } cast_mode |= CM_FORMAT_NUMBER_WITH_LIMIT; LOG_DEBUG("in get_defalut_cast_mode", K(ret), K(is_explicit_cast), K(result_flag), K(session->get_stmt_type()), K(cast_mode)); } return ret; } int ObSQLUtils::check_well_formed_str(const ObString& src_str, const ObCollationType cs_type, ObString& dst_str, bool& is_null, const bool is_strict_mode, const bool ret_error) { int ret = OB_SUCCESS; // make sure src_str is from varchar obj is_null = false; int64_t str_len = src_str.length(); int64_t well_formed_length = 0; int32_t well_formed_error = 0; if (CS_TYPE_INVALID == cs_type) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid collation type", K(ret), K(src_str), K(cs_type)); } else if (OB_FAIL( ObCharset::well_formed_len(cs_type, src_str.ptr(), str_len, well_formed_length, well_formed_error))) { LOG_WARN("fail to check well_formed_len", K(ret), K(src_str), K(cs_type)); } else if (well_formed_length < str_len) { int32_t diff = static_cast(str_len - well_formed_length); diff = diff > 3 ? 3 : diff; char hex_buf[7] = {0}; int64_t hex_len = 0; const char* charset_name = ObCharset::charset_name(cs_type); int64_t charset_name_len = strlen(charset_name); if (OB_FAIL(common::hex_print(src_str.ptr() + well_formed_length, diff, hex_buf, sizeof(hex_buf), hex_len))) { LOG_WARN("Failed to transform to hex cstr", K(ret), K(src_str), K(well_formed_length)); } else if (ret_error) { ret = OB_ERR_INVALID_CHARACTER_STRING; LOG_USER_ERROR(OB_ERR_INVALID_CHARACTER_STRING, (int)charset_name_len, charset_name, (int)hex_len, hex_buf); } else if (is_strict_mode) { dst_str.reset(); is_null = true; } else { dst_str.assign_ptr(src_str.ptr(), static_cast(well_formed_length)); } if (OB_SUCC(ret)) { LOG_USER_WARN(OB_ERR_INVALID_CHARACTER_STRING, static_cast(charset_name_len), charset_name, static_cast(hex_len), hex_buf); } } else { dst_str = src_str; } return ret; } int ObSQLUtils::check_well_formed_str(const ObObj& src, ObObj& dest, const bool is_strict_mode, const bool ret_error) { int ret = OB_SUCCESS; if (!src.is_varchar_or_char() && !src.is_varbinary() && !src.is_binary()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(src)); } else { ObString src_str; ObString dst_str; bool is_null = false; if (OB_FAIL(src.get_varchar(src_str))) { LOG_WARN("fail to get varchar", K(ret), K(src)); } else if (OB_FAIL(check_well_formed_str( src_str, src.get_collation_type(), dst_str, is_null, is_strict_mode, ret_error))) { LOG_WARN("check_well_formed_str failed", K(ret), K(src_str), K(is_strict_mode), K(ret_error)); } else if (is_null) { dest.set_null(); } else { dest.set_varchar(dst_str); dest.set_collation_level(src.get_collation_level()); dest.set_collation_type(src.get_collation_type()); } } return ret; } int ObSQLUtils::get_outline_key(ObIAllocator& allocator, const ObSQLSessionInfo* session, const ObString& query_sql, ObString& outline_key, ObMaxConcurrentParam::FixParamStore& fix_param_store, ParseMode parse_mode, bool& has_questionmark_in_sql) { int ret = OB_SUCCESS; has_questionmark_in_sql = false; if (OB_ISNULL(session)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument, session is NULL", K(ret)); } else { ObString no_param_sql; ParseResult parse_result; ObParser parser(allocator, session->get_sql_mode(), session->get_local_collation_connection()); ObSEArray special_params; ObString param_sql; const int64_t PARAM_COUNT = 128; ParamStore params((ObWrapperAllocator(allocator))); ObSqlTraits sql_traits; ObSEArray raw_params; SqlInfo sql_info; char* buf = NULL; int32_t pos = 0; const bool is_transform_outline = true; ParseNode* type_node = NULL; if (OB_FAIL(parser.parse(query_sql, parse_result))) { LOG_WARN("Generate syntax tree failed", "sql", query_sql, K(ret)); } else if (OB_ISNULL(parse_result.result_tree_)) { ret = OB_NOT_INIT; LOG_WARN("parse result tree not inited", K(parse_result.result_tree_), K(ret)); } else if (OB_ISNULL(parse_result.result_tree_->children_) || OB_UNLIKELY(parse_result.result_tree_->num_child_ < 1)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid args", K(ret), KP(parse_result.result_tree_->children_), "number of children", parse_result.result_tree_->num_child_); } else if (NULL == (type_node = parse_result.result_tree_->children_[0])) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid args", K(type_node)); } else if (!IS_DML_STMT(type_node->type_)) { ret = OB_SQL_DML_ONLY; LOG_TRACE("statement not dml sql", K(type_node)); } else if (OB_FAIL(ObSqlParameterization::transform_syntax_tree(allocator, *session, NULL, 0, parse_result.result_tree_, sql_info, params, NULL, fix_param_store, is_transform_outline))) { if (OB_NOT_SUPPORTED != ret) { SQL_PC_LOG(WARN, "fail to tranform syntax_tree", K(ret)); } } else if (OB_FAIL(ObSqlParameterization::raw_fast_parameterize_sql( allocator, *session, query_sql, no_param_sql, raw_params, parse_mode))) { LOG_WARN("fail to fast_parameterize_sql", K(ret)); } else if (OB_FAIL(ObSqlParameterization::check_and_generate_param_info(raw_params, sql_info, special_params))) { if (OB_NOT_SUPPORTED == ret) { LOG_TRACE("fail to check and generate not params", K(ret), K(query_sql), K(no_param_sql)); } else { LOG_WARN("fail to check and generate not params", K(ret), K(query_sql), K(no_param_sql)); } } else if (OB_UNLIKELY(NULL == (buf = (char*)allocator.alloc(query_sql.length())))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("fail to alloc buf", K(ret)); } else if (OB_FAIL( ObSqlParameterization::construct_sql(no_param_sql, special_params, buf, query_sql.length(), pos))) { LOG_WARN("fail to construct_sql", K(ret), K(no_param_sql), K(special_params.count())); } else { ObString constructed_sql(pos, buf); int64_t size = constructed_sql.get_serialize_size(); if (0 == size) { ret = OB_ERR_UNEXPECTED; } else { char* buf = NULL; int64_t pos_s = 0; if (OB_UNLIKELY(NULL == (buf = (char*)allocator.alloc(size)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("fail to alloc mem", K(ret)); } else if (OB_FAIL(constructed_sql.serialize(buf, size, pos_s))) { LOG_WARN("fail to serialize key", K(ret)); } else { outline_key.assign_ptr(buf, static_cast(pos_s)); if (params.count() != fix_param_store.count()) { has_questionmark_in_sql = true; } } } } parser.free_result(parse_result); } return ret; } int ObSQLUtils::filter_hint_in_query_sql( ObIAllocator& allocator, const ObSQLSessionInfo& session, const ObString& sql, ObString& param_sql) { int ret = OB_SUCCESS; ObParser parser(allocator, session.get_sql_mode(), session.get_local_collation_connection()); ParseResult parse_result; if (OB_FAIL(parser.parse(sql, parse_result, FP_NO_PARAMERIZE_AND_FILTER_HINT_MODE))) { SQL_PC_LOG(WARN, "fail to parse query while filter hint", K(ret)); } else { param_sql.assign(parse_result.no_param_sql_, parse_result.no_param_sql_len_); parser.free_result(parse_result); } return ret; } int ObSQLUtils::construct_outline_sql(ObIAllocator& allocator, const ObSQLSessionInfo& session, const ObString& outline_content, const ObString& orig_sql, bool is_need_filter_hint, ObString& outline_sql) { int ret = OB_SUCCESS; UNUSED(is_need_filter_hint); ObString filter_sql; ObSqlString sql_helper; int first_token_len = 0; if (OB_FAIL(filter_hint_in_query_sql(allocator, session, orig_sql, filter_sql))) { LOG_WARN("fail to filter hint", K(ret)); } else if (OB_FAIL(filter_head_space(filter_sql))) { LOG_WARN("fail to filter head space", K(ret)); } if (OB_SUCC(ret)) { char empty_split = find_first_empty_char(filter_sql); ObString first_token = filter_sql.split_on(empty_split); if (OB_FAIL(sql_helper.assign_fmt("%.*s %.*s%.*s", first_token.length(), first_token.ptr(), outline_content.length(), outline_content.ptr(), filter_sql.length(), filter_sql.ptr()))) { LOG_WARN("failed to construct new sql", K(first_token), K(orig_sql), K(filter_sql), K(outline_content), K(ret)); } else if (OB_FAIL(ob_write_string(allocator, sql_helper.string(), outline_sql))) { LOG_WARN("failed to write string", K(first_token), K(orig_sql), K(filter_sql), K(outline_content), K(ret)); } else { /*do nothing*/ } } return ret; } int ObSQLUtils::filter_head_space(ObString& sql) { int ret = OB_SUCCESS; int64_t head_space_len = 0; bool is_space = true; for (int64_t i = 0; is_space && i < sql.length(); i++) { char ch = sql[i]; if (' ' == ch || '\r' == ch || '\n' == ch || '\t' == ch || '\f' == ch) { ++head_space_len; } else { is_space = false; } } sql.assign(sql.ptr() + head_space_len, sql.length() - head_space_len); return ret; } char ObSQLUtils::find_first_empty_char(const ObString &sql) { char empty_char = ' '; // default split for (int64_t i = 0; i < sql.length(); ++i) { char ch = sql[i]; if (' ' == ch || '\r' == ch || '\n' == ch || '\t' == ch || '\f' == ch) { empty_char = ch; break; } } return empty_char; } int ObSQLUtils::reconstruct_sql(ObIAllocator &allocator, const ObStmt *stmt, ObString &sql, ObObjPrintParams print_params) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("stmt is NULL", K(stmt), K(ret)); } else if (!stmt->is_dml_stmt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected stmt type", K(stmt->get_stmt_type()), K(stmt->get_sql_stmt()), K(ret)); } else { SMART_VAR(char[OB_MAX_SQL_LENGTH], buf) { int64_t buf_len = OB_MAX_SQL_LENGTH; int64_t pos = 0; switch (stmt->get_stmt_type()) { case stmt::T_SELECT: { bool is_set_subquery = false; ObSelectStmtPrinter printer( buf, buf_len, &pos, static_cast(stmt), print_params, NULL, is_set_subquery); if (OB_FAIL(printer.do_print())) { LOG_WARN("fail to print select stmt", K(ret)); } else if (OB_FAIL(ob_write_string(allocator, ObString(pos, buf), sql))) { LOG_WARN("fail to deep copy select stmt string", K(ret)); } else { /*do nothing*/ } } break; case stmt::T_INSERT: { ObInsertStmtPrinter printer(buf, buf_len, &pos, static_cast(stmt), print_params); if (OB_FAIL(printer.do_print())) { LOG_WARN("fail to print insert stmt", K(ret)); } else if (OB_FAIL(ob_write_string(allocator, ObString(pos, buf), sql))) { LOG_WARN("fail to deep copy insert stmt string", K(ret)); } else { /*do nothing*/ } } break; case stmt::T_REPLACE: { } break; case stmt::T_DELETE: { ObDeleteStmtPrinter printer(buf, buf_len, &pos, static_cast(stmt), print_params); if (OB_FAIL(printer.do_print())) { LOG_WARN("fail to print delete stmt", K(ret)); } else if (OB_FAIL(ob_write_string(allocator, ObString(pos, buf), sql))) { LOG_WARN("fail to deep copy delete stmt string", K(ret)); } else { /*do nothing*/ } } break; case stmt::T_UPDATE: { ObUpdateStmtPrinter printer(buf, buf_len, &pos, static_cast(stmt), print_params); if (OB_FAIL(printer.do_print())) { LOG_WARN("fail to print update stmt", K(ret)); } else if (OB_FAIL(ob_write_string(allocator, ObString(pos, buf), sql))) { LOG_WARN("fail to deep copy update stmt string", K(ret)); } else { /*do nothing*/ } } break; case stmt::T_MERGE: { ObMergeStmtPrinter printer(buf, buf_len, &pos, static_cast(stmt), print_params); if (OB_FAIL(printer.do_print())) { LOG_WARN("failed to print merge stmt", K(ret)); } else if (OB_FAIL(ob_write_string(allocator, ObString(pos, buf), sql))) { LOG_WARN("failed to deep copy merge stmt string", K(ret)); } } break; default: { ret = OB_NOT_SUPPORTED; LOG_WARN("Invalid stmt type", K(stmt->get_stmt_type()), K(stmt->get_sql_stmt()), K(ret)); } break; } } } return ret; } int ObSQLUtils::wrap_expr_ctx(const stmt::StmtType& stmt_type, ObExecContext& exec_ctx, common::ObIAllocator& allocator, common::ObExprCtx& expr_ctx) { int ret = OB_SUCCESS; ObSQLSessionInfo* my_session = NULL; const ObTimeZoneInfo* tz_info = NULL; int64_t tz_offset = 0; if (OB_ISNULL(my_session = exec_ctx.get_my_session())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else if (OB_ISNULL(tz_info = get_timezone_info(my_session))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get tz info pointer failed", K(ret)); } else if (OB_FAIL(get_tz_offset(tz_info, tz_offset))) { LOG_WARN("get tz offset failed", K(ret)); } else if (OB_FAIL(get_default_cast_mode(stmt_type, my_session, expr_ctx.cast_mode_))) { LOG_WARN("Failed to get default cast mode", K(ret)); } else { expr_ctx.exec_ctx_ = &exec_ctx; expr_ctx.calc_buf_ = &allocator; expr_ctx.phy_plan_ctx_ = exec_ctx.get_physical_plan_ctx(); expr_ctx.my_session_ = my_session; expr_ctx.tz_offset_ = tz_offset; if (OB_FAIL(wrap_column_convert_ctx(expr_ctx, expr_ctx.column_conv_ctx_))) { LOG_WARN("wrap column convert ctx failed", K(ret)); } } return ret; } bool ObSQLUtils::is_same_type(const ObExprResType& type1, const ObExprResType& type2) { return is_same_type(type1.get_obj_meta(), type2.get_obj_meta(), type1.get_accuracy(), type2.get_accuracy()); } bool ObSQLUtils::is_same_type( const ObObjMeta& meta1, const ObObjMeta& meta2, const ObAccuracy& accuracy1, const ObAccuracy& accuracy2) { return meta1.get_type() == meta2.get_type() && meta1.get_collation_type() == meta2.get_collation_type() && meta1.get_scale() == meta2.get_scale() && accuracy1 == accuracy2; } const int32_t RelExprCheckerBase::FIELD_LIST_SCOPE = 1 << 1; const int32_t RelExprCheckerBase::WHERE_SCOPE = 1 << 2; // const int32_t RelExprCheckerBase::ON_SCOPE = 1<<3; const int32_t RelExprCheckerBase::GROUP_SCOPE = 1 << 4; const int32_t RelExprCheckerBase::HAVING_SCOPE = 1 << 5; // const int32_t RelExprCheckerBase::INSERT_SCOPE = 1<<6; // const int32_t RelExprCheckerBase::UPDATE_SCOPE = 1<<7; // const int32_t RelExprCheckerBase::AGG_SCOPE = 1<<8; // const int32_t RelExprCheckerBase::VARIABLE_SCOPE = 1<<9; // const int32_t RelExprCheckerBase::WHEN_SCOPE = 1<<10; const int32_t RelExprCheckerBase::ORDER_SCOPE = 1 << 11; // const int32_t RelExprCheckerBase::EXPIRE_SCOPE = 1<<12; // const int32_t RelExprCheckerBase::PARTITION_SCOPE = 1<<13; const int32_t RelExprCheckerBase::FROM_SCOPE = 1 << 14; const int32_t RelExprCheckerBase::LIMIT_SCOPE = 1 << 15; // const int32_t RelExprCheckerBase::PARTITION_RANGE_SCOPE = 1<<16; // const int32_t RelExprCheckerBase::INTO_SCOPE = 1<<17; const int32_t RelExprCheckerBase::START_WITH_SCOPE = 1 << 18; const int32_t RelExprCheckerBase::CONNECT_BY_SCOPE = 1 << 19; const int32_t RelExprCheckerBase::JOIN_CONDITION_SCOPE = 1 << 20; const int32_t RelExprCheckerBase::EXTRA_OUTPUT_SCOPE = 1 << 21; int RelExprCheckerBase::init(int64_t bucket_num) { return duplicated_checker_.create(bucket_num); } int RelExprCheckerBase::add_exprs(common::ObIArray& exprs) { int ret = common::OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) { if (OB_FAIL(add_expr(exprs.at(i)))) { LOG_WARN("add expression to relation expr checker failed", K(ret)); } } return ret; } int RelExprChecker::add_expr(ObRawExpr*& expr) { int ret = OB_SUCCESS; if (OB_HASH_NOT_EXIST == (ret = duplicated_checker_.exist_refactored(reinterpret_cast(expr)))) { if (OB_FAIL(duplicated_checker_.set_refactored(reinterpret_cast(expr)))) { LOG_WARN("set expr to duplicated checker failed", K(ret), K(duplicated_checker_.size())); } else if (OB_FAIL(rel_array_.push_back(expr))) { LOG_WARN("push expr to relation array failed", K(ret)); } } else if (OB_HASH_EXIST == ret) { ret = OB_SUCCESS; } else { LOG_WARN("check expr in duplicated checker", K(ret)); } return ret; } FastRelExprChecker::FastRelExprChecker(common::ObIArray& rel_array) : RelExprCheckerBase(), rel_array_(rel_array), init_size_(rel_array.count()) {} FastRelExprChecker::FastRelExprChecker(common::ObIArray& rel_array, int32_t ignore_scope) : RelExprCheckerBase(ignore_scope), rel_array_(rel_array), init_size_(rel_array.count()) {} FastRelExprChecker::~FastRelExprChecker() { for (int64_t i = init_size_; i < rel_array_.count(); ++i) { if (OB_ISNULL(rel_array_.at(i))) { // do nothing } else { rel_array_.at(i)->clear_flag(BE_USED); } } } int FastRelExprChecker::add_expr(ObRawExpr*& expr) { int ret = OB_SUCCESS; if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is invalid", K(ret)); } else if (expr->has_flag(BE_USED)) { // do nothing } else if (OB_FAIL(rel_array_.push_back(expr))) { LOG_WARN("failed to push back expr", K(ret)); } else if (OB_FAIL(expr->add_flag(BE_USED))) { LOG_WARN("failed to add flag", K(ret)); } return ret; } int RelExprPointerChecker::init(int64_t bucket_num) { return expr_id_map_.create(bucket_num, common::ObModIds::OB_SQL_EXPR); } int RelExprPointerChecker::add_expr(ObRawExpr*& expr) { int ret = OB_SUCCESS; int flag = 0; uint64_t expr_id = UINT64_MAX; if (OB_HASH_NOT_EXIST == (flag = expr_id_map_.get_refactored(reinterpret_cast(expr), expr_id))) { ObRawExprPointer pointer; if (OB_FAIL(rel_array_.push_back(pointer))) { LOG_WARN("failed to push back new array", K(ret)); } else { expr_id = rel_array_.count() - 1; } } else if (OB_HASH_EXIST == flag) { // do nothing } else { ret = flag; LOG_WARN("failed to get from hash map", K(ret)); } if (OB_SUCC(ret) && expr_id < rel_array_.count()) { if (OB_FAIL(rel_array_.at(expr_id).add_ref(&expr))) { LOG_WARN("failed to push expr into array", K(ret)); } } return ret; } int AllExprPointerCollector::add_expr(ObRawExpr*& expr) { int ret = OB_SUCCESS; if (OB_FAIL(rel_array_.push_back(&expr))) { LOG_WARN("push expr to relation array failed", K(ret)); } return ret; } ObSqlTraits::ObSqlTraits() : is_readonly_stmt_(false), is_modify_tenant_stmt_(false), is_cause_implicit_commit_(false), is_commit_stmt_(false), stmt_type_(T_INVALID) { sql_id_[common::OB_MAX_SQL_ID_LENGTH] = '\0'; } // used for C module bool check_stack_overflow_c() { bool is_overflow = false; int ret = OB_SUCCESS; if (OB_FAIL(oceanbase::common::check_stack_overflow(is_overflow))) { LOG_ERROR("fail to check stack overflow", K(ret)); } return is_overflow; } int ObSQLUtils::get_partition_service(ObTaskExecutorCtx& executor_ctx, int64_t table_id, ObIDataAccessService*& das) { int ret = OB_SUCCESS; if (is_virtual_table(table_id)) { das = executor_ctx.get_vt_partition_service(); } else { das = static_cast(executor_ctx.get_partition_service()); } if (OB_ISNULL(das)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get data access service", K(ret), K(table_id)); } LOG_TRACE("get data access service", K(table_id)); return ret; } /*int ObSQLUtils::calculate_phy_table_location(ObExecContext &exec_ctx, ObPartMgr *part_mgr, const ObIArray ¶ms, ObIPartitionLocationCache &location_cache, const ObTimeZoneInfo *tz_info, ObTableLocation &table_location, ObPhyTableLocation &phy_location) { int ret = OB_SUCCESS; if (OB_FAIL(table_location.calculate_partition_locations(exec_ctx, part_mgr, params, location_cache, phy_location.get_partition_location_list(), tz_info))) { LOG_WARN("Failed to calculate table location", K(ret)); } else if (OB_FAIL(phy_location.fill_part_loc_list())) { LOG_WARN("Failed to fill part loc list", K(ret), K(phy_location)); } else { phy_location.set_table_location_key(table_location.get_table_id(), table_location.get_ref_table_id()); } return ret; }*/ /* * duplicated with * int ObQueryRange::get_tablet_ranges(common::ObIAllocator &allocator, * const ParamsIArray ¶ms, * ObQueryRangeArray &ranges, * bool &all_single_value_ranges, * const common::ObTimeZoneInfo *tz_info) const */ int ObSQLUtils::extract_pre_query_range(const ObQueryRange& pre_query_range, ObIAllocator& allocator, const ParamStore& param_store, ObQueryRangeArray& key_ranges, ObGetMethodArray get_method, const ObDataTypeCastParams& dtc_params, common::ObIArray* range_pos) { int ret = OB_SUCCESS; if (OB_LIKELY(!pre_query_range.need_deep_copy())) { if (OB_FAIL( pre_query_range.get_tablet_ranges(allocator, param_store, key_ranges, get_method, dtc_params, range_pos))) { LOG_WARN("fail to get tablet ranges", K(ret)); } } else { ObQueryRange final_query_range(allocator); if (OB_FAIL(final_query_range.deep_copy(pre_query_range))) { // MUST deep copy to make it thread safe LOG_WARN("fail to create final query range", K(ret), K(pre_query_range)); } else if (OB_FAIL(final_query_range.final_extract_query_range(param_store, dtc_params))) { LOG_WARN("fail to final extract query range", K(ret), K(final_query_range)); } else if (OB_FAIL(final_query_range.get_tablet_ranges(key_ranges, get_method, dtc_params))) { LOG_WARN("fail to get tablet ranges from query range", K(ret), K(final_query_range)); } else { // do nothing } } return ret; } int ObSQLUtils::get_partition_range(ObObj* start_row_key, ObObj* end_row_key, ObObj* function_obj, const share::schema::ObPartitionFuncType part_type, const ObSqlExpression& part_expr, int64_t range_key_count, uint64_t table_id, ObExprCtx& expr_ctx, common::ObNewRange& part_range) { int ret = OB_SUCCESS; if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_RANGE_COLUMNS || part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_LIST_COLUMNS || part_expr.is_empty()) { part_range.table_id_ = table_id; part_range.start_key_.assign(start_row_key, range_key_count); part_range.end_key_.assign(end_row_key, range_key_count); part_range.border_flag_.set_inclusive_start(); part_range.border_flag_.set_inclusive_end(); if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH || part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH_V2) { // hash partition and part_expr.is_empty(), should not reach here LOG_TRACE("get empty part_expr"); ObNewRow start_row; start_row.cells_ = start_row_key; start_row.count_ = range_key_count; ObNewRow end_row; end_row.cells_ = end_row_key; end_row.count_ = range_key_count; if (OB_FAIL(ObSQLUtils::revise_hash_part_object(start_row_key[0], start_row, true, part_type))) { LOG_WARN("failed to revise hash part object", K(ret)); } else if (OB_FAIL(ObSQLUtils::revise_hash_part_object(end_row_key[0], end_row, true, part_type))) { LOG_WARN("failed to revise hash part object", K(ret)); } else { /*do nothing*/ } } } else { LOG_TRACE("get non empty part_expr"); ObNewRow input_row; ObNewRow dummy_row; input_row.cells_ = start_row_key; input_row.count_ = range_key_count; if (OB_FAIL(part_expr.calc(expr_ctx, input_row, *function_obj))) { LOG_WARN("failed to calc expr", K(ret)); } else if (FALSE_IT(dummy_row.cells_ = function_obj)) { } else if (FALSE_IT(dummy_row.count_ = 1)) { } else if ((part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH || part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH_V2) && OB_FAIL(ObSQLUtils::revise_hash_part_object(*function_obj, dummy_row, false, part_type))) { LOG_WARN("failed to revise hash partition object", K(ret)); } else { part_range.table_id_ = table_id; part_range.start_key_.assign(function_obj, 1); part_range.end_key_.assign(function_obj, 1); part_range.border_flag_.set_inclusive_start(); part_range.border_flag_.set_inclusive_end(); } } return ret; } int ObSQLUtils::get_partition_range(ObObj* start_row_key, ObObj* end_row_key, ObObj* function_obj, const share::schema::ObPartitionFuncType part_type, const ObExpr* part_expr, int64_t range_key_count, uint64_t table_id, ObEvalCtx& eval_ctx, common::ObNewRange& part_range) { int ret = OB_SUCCESS; if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_RANGE_COLUMNS || part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_LIST_COLUMNS || OB_ISNULL(part_expr)) { part_range.table_id_ = table_id; part_range.start_key_.assign(start_row_key, range_key_count); part_range.end_key_.assign(end_row_key, range_key_count); part_range.border_flag_.set_inclusive_start(); part_range.border_flag_.set_inclusive_end(); if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH || part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH_V2) { // hash partition and part_expr.is_empty(), should not reach here LOG_TRACE("get empty part_expr"); ObNewRow start_row; start_row.cells_ = start_row_key; start_row.count_ = range_key_count; ObNewRow end_row; end_row.cells_ = end_row_key; end_row.count_ = range_key_count; if (OB_FAIL(ObSQLUtils::revise_hash_part_object(start_row_key[0], start_row, true, part_type))) { LOG_WARN("failed to revise hash part object", K(ret)); } else if (OB_FAIL(ObSQLUtils::revise_hash_part_object(end_row_key[0], end_row, true, part_type))) { LOG_WARN("failed to revise hash part object", K(ret)); } else { /*do nothing*/ } } } else { LOG_TRACE("get non empty part_expr"); ObNewRow dummy_row; ObDatum* datum = NULL; if (OB_FAIL(part_expr->eval(eval_ctx, datum))) { LOG_WARN("failed to calc expr", K(ret)); } else if (OB_FAIL(datum->to_obj(*function_obj, part_expr->obj_meta_, part_expr->obj_datum_map_))) { LOG_WARN("convert datum to obj failed", K(ret)); } else if (FALSE_IT(dummy_row.cells_ = function_obj)) { } else if (FALSE_IT(dummy_row.count_ = 1)) { } else if ((part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH || part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH_V2) && OB_FAIL(ObSQLUtils::revise_hash_part_object(*function_obj, dummy_row, false, part_type))) { LOG_WARN("failed to revise hash partition object", K(ret)); } else { part_range.table_id_ = table_id; part_range.start_key_.assign(function_obj, 1); part_range.end_key_.assign(function_obj, 1); part_range.border_flag_.set_inclusive_start(); part_range.border_flag_.set_inclusive_end(); } } return ret; } int ObSQLUtils::revise_hash_part_object(common::ObObj& obj, const ObNewRow& row, const bool calc_oracle_hash, const share::schema::ObPartitionFuncType part_type) { int ret = OB_SUCCESS; ObObj result; if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH) { if (share::is_oracle_mode()) { if (calc_oracle_hash) { ret = ObExprFuncPartOldHash::calc_value_for_oracle(row.cells_, row.count_, result); } else { result = obj; } } else { ret = ObExprFuncPartOldHash::calc_value_for_mysql(obj, result); } } else { if (share::is_oracle_mode()) { if (calc_oracle_hash) { ret = ObExprFuncPartHash::calc_value_for_oracle(row.cells_, row.count_, result); } else { result = obj; } } else { ret = ObExprFuncPartHash::calc_value_for_mysql(obj, result); } } if (OB_SUCC(ret)) { obj.set_int(result.get_int()); } return ret; } int ObSQLUtils::choose_best_partition_for_estimation(const ObPhyPartitionLocationInfoIArray& part_loc_info_array, const common::ObAddr& addr, common::ObPartitionKey& key, bool& has_local) { common::ObStatManager& stat_manager = common::ObStatManager::get_instance(); return choose_best_partition_for_estimation(part_loc_info_array, addr, key, stat_manager, has_local); } int ObSQLUtils::choose_best_partition_for_estimation(const ObPhyPartitionLocationInfoIArray& part_loc_info_array, const common::ObAddr& addr, common::ObPartitionKey& key, common::ObStatManager& stat_manager, bool& has_local) { int ret = OB_SUCCESS; has_local = false; ObSEArray local_partition_keys; ObSEArray all_partition_keys; if (OB_FAIL(ObSQLUtils::find_all_local_replica(part_loc_info_array, addr, local_partition_keys))) { LOG_WARN("failed to find all local replica", K(ret)); } else { // try to find best local partition for estimation int64_t local_max_count = -1; if (OB_SUCC(ret) && local_partition_keys.count() > 0) { has_local = true; common::ObTableStat tstat; for (int64_t i = 0; OB_SUCC(ret) && i < local_partition_keys.count(); i++) { if (OB_FAIL(stat_manager.get_table_stat(local_partition_keys.at(i), tstat))) { LOG_WARN("failed to get table stat", K(ret)); } else if (tstat.get_row_count() > local_max_count) { local_max_count = tstat.get_row_count(); key = local_partition_keys.at(i); } else { /*do nothing*/ } } } // if we do not have local partition or the largest local partition is empty, use the largest non_local partition // for estimation if (OB_SUCC(ret) && (!has_local || local_max_count == 0)) { int64_t all_max_count = -1; common::ObTableStat tstat; common::ObPartitionKey temp_key; for (int64_t i = 0; OB_SUCC(ret) && i < part_loc_info_array.count(); i++) { if (OB_FAIL(part_loc_info_array.at(i).get_partition_location().get_partition_key(temp_key))) { LOG_WARN("Get partition key error", "partition info", part_loc_info_array.at(0), K(ret)); } else if (OB_FAIL(all_partition_keys.push_back(temp_key))) { LOG_WARN("failed to push back partition key", K(ret)); } else { /*do nothing*/ } } for (int64_t i = 0; OB_SUCC(ret) && i < all_partition_keys.count(); i++) { if (OB_FAIL(stat_manager.get_table_stat(all_partition_keys.at(i), tstat))) { LOG_WARN("failed to get table stat", K(ret)); } else if (tstat.get_row_count() > all_max_count) { all_max_count = tstat.get_row_count(); temp_key = all_partition_keys.at(i); } else { /*do nothing*/ } } if (OB_SUCC(ret)) { if (has_local && all_max_count == 0) { /*do nothing*/ } else { has_local = false; key = temp_key; } } } } return ret; } int ObSQLUtils::choose_best_partition_for_estimation(const ObPhyPartitionLocationInfoIArray& part_loc_info_array, storage::ObPartitionService* partition_service, ObStatManager& stat_manager, const ObAddr& local_addr, const common::ObIArray& addrs_list, const bool no_use_new, EstimatedPartition& best_partition) { int ret = OB_SUCCESS; int64_t max_row_count = -1; int64_t part_idx = -1; ObPartitionKey part_pkey; best_partition.reset(); if (OB_UNLIKELY(part_loc_info_array.empty())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("partition array is empty", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < part_loc_info_array.count(); ++i) { const ObOptPartLoc& part_loc = part_loc_info_array.at(i).get_partition_location(); ObPartitionKey key; common::ObTableStat tstat; if (OB_FAIL(part_loc.get_partition_key(key))) { LOG_WARN("fail to get partition key", K(ret)); } else if (OB_FAIL(stat_manager.get_table_stat(key, tstat))) { // reminder: stat manager get statisics from both local storage and // __all_meta_table (inner table) LOG_WARN("failed to get table stat", K(ret)); } else { LOG_TRACE("partition info", K(i), K(key), K(tstat.get_row_count())); } if (OB_FAIL(ret) || tstat.get_row_count() <= max_row_count) { // do nothing } else { // 1. get partition has largest row count max_row_count = tstat.get_row_count(); part_idx = i; part_pkey = key; } } // for part_array end if (OB_FAIL(ret)) { // do nothing } else if (OB_UNLIKELY(-1 == part_idx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("part idx should larger than -1", K(ret)); } else { const ObOptPartLoc& part_loc = part_loc_info_array.at(part_idx).get_partition_location(); const ObIArray& replica_loc_array = part_loc.get_replica_locations(); bool found = false; // 2. check whether best partition can find in local for (int64_t k = -1; !found && k < addrs_list.count(); ++k) { for (int64_t j = 0; !found && j < replica_loc_array.count(); ++j) { const ObAddr& addr = (k == -1 ? local_addr : addrs_list.at(k)); if (addr == replica_loc_array.at(j).server_ && 0 != replica_loc_array.at(j).property_.get_memstore_percent()) { found = true; best_partition.set(part_pkey, addr, max_row_count); } } } if (!found) { // best partition not find in local ObAddr remote_addr; if (no_use_new) { // do nothing } else if (OB_FAIL(choose_best_partition_replica_addr( local_addr, part_loc_info_array.at(part_idx), partition_service, remote_addr))) { LOG_WARN("failed to get best partition replica addr", K(ret)); ret = OB_SUCCESS; } if (OB_SUCC(ret)) { best_partition.set(part_pkey, remote_addr, max_row_count); } } } return ret; } int ObSQLUtils::choose_best_partition_replica_addr(const ObAddr& local_addr, const ObPhyPartitionLocationInfo& phy_part_loc_info, storage::ObPartitionService* partition_service, ObAddr& selected_addr) { int ret = OB_SUCCESS; selected_addr.reset(); ObServerLocality local_locality; ObSEArray all_server_arr; bool has_read_only_zone = false; // UNUSED; if (OB_ISNULL(partition_service)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL param", K(ret), K(partition_service)); } else if (OB_FAIL(partition_service->get_server_locality_array(all_server_arr, has_read_only_zone))) { LOG_WARN("fail to get server locality", K(ret)); } else if (OB_FAIL(ObRoutePolicy::get_server_locality(local_addr, all_server_arr, local_locality))) { LOG_WARN("fail to get local locality", K(ret)); } else { bool need_continue = true; const ObIArray& candi_replicas = phy_part_loc_info.get_partition_location().get_replica_locations(); ObSEArray same_idc_addr; ObSEArray same_region_addr; ObSEArray other_region_addr; for (int64_t i = 0; need_continue && OB_SUCC(ret) && i < candi_replicas.count(); ++i) { ObServerLocality candi_locality; const ObAddr& candi_addr = candi_replicas.at(i).server_; if (candi_replicas.at(i).property_.get_memstore_percent() == 0) { // skip replica whose memstore percent is zero } else if (OB_FAIL(ObRoutePolicy::get_server_locality(candi_addr, all_server_arr, candi_locality))) { LOG_WARN("fail to get server locality", K(all_server_arr), K(candi_addr), K(ret)); } else if (OB_UNLIKELY(!candi_locality.is_init())) { // not find // do nothing } else if (!candi_locality.is_active() || ObServerStatus::OB_SERVER_ACTIVE != candi_locality.get_server_status() || 0 == candi_locality.get_start_service_time() || 0 != candi_locality.get_server_stop_time()) { // server may not serving } else if (local_addr == candi_addr) { selected_addr = candi_addr; need_continue = false; } else if (local_locality.is_init() && ObRoutePolicy::is_same_idc(local_locality, candi_locality)) { if (OB_FAIL(same_idc_addr.push_back(candi_addr))) { LOG_WARN("failed to push back same idc candidate address", K(ret)); } } else if (local_locality.is_init() && ObRoutePolicy::is_same_region(local_locality, candi_locality)) { if (OB_FAIL(same_region_addr.push_back(candi_addr))) { LOG_WARN("failed to push back same region candidate address", K(ret)); } } else if (OB_FAIL(other_region_addr.push_back(candi_addr))) { LOG_WARN("failed to push back other region candidate address", K(ret)); } } if (OB_SUCC(ret)) { if (selected_addr.is_valid()) { // do noting, find local addr LOG_TRACE("has local replica", K(selected_addr)); } else if (!same_idc_addr.empty()) { int64_t selected_idx = rand() % same_idc_addr.count(); selected_addr = same_idc_addr.at(selected_idx); LOG_TRACE("has same idc replica", K(selected_addr)); } else if (!same_region_addr.empty()) { int64_t selected_idx = rand() % same_region_addr.count(); selected_addr = same_region_addr.at(selected_idx); LOG_TRACE("has same region replica", K(selected_addr)); } else if (!other_region_addr.empty()) { int64_t selected_idx = rand() % other_region_addr.count(); selected_addr = other_region_addr.at(selected_idx); LOG_TRACE("has other region replica", K(selected_addr)); } else { ret = OB_WORKING_PARTITION_NOT_EXIST; LOG_WARN("No useful replica found", K(ret)); } } } return ret; } int ObSQLUtils::has_global_index( share::schema::ObSchemaGetterGuard* schema_guard, const uint64_t table_id, bool& exists) { int ret = OB_SUCCESS; const ObTableSchema* index_schema = NULL; uint64_t index_ids[OB_MAX_INDEX_PER_TABLE + 1]; int64_t index_count = OB_MAX_INDEX_PER_TABLE + 1; exists = false; if (OB_ISNULL(schema_guard)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("null schema guard", K(ret)); } else if (OB_FAIL(schema_guard->get_can_read_index_array(table_id, index_ids, index_count, false))) { LOG_WARN("failed to get can read index", K(ret)); } else if (index_count > OB_MAX_INDEX_PER_TABLE + 1) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table index count is bigger than OB_MAX_INDEX_PER_TABLE", K(ret), K(index_count)); } else { for (int64_t i = 0; OB_SUCC(ret) && !exists && i < index_count; i++) { if (OB_FAIL(schema_guard->get_table_schema(index_ids[i], index_schema))) { LOG_WARN("failed to get index schema", K(ret)); } else if (OB_ISNULL(index_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null index schema", K(ret)); } else if (index_schema->is_global_index_table()) { exists = true; } else { /*do nothing*/ } } } LOG_TRACE("finish to check whether table has global index", K(exists), K(table_id)); return ret; } int ObSQLUtils::wrap_column_convert_ctx(const ObExprCtx& expr_ctx, ObCastCtx& column_conv_ctx) { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.my_session_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected error. null session", K(expr_ctx.my_session_), K(ret)); } else { // is_strict == true is_ignore_stmt == true then cast_mode = CM_WARN_ON_FAIL // is_strict == true is_ignore_stmt == false then cast_mode = CM_NONE // is_strict == false is_ignore_stmt == true then cast_mode = CM_NO_RANGE_CHECK & CM_WARN_ON_FAIL // is_strict == false is_ignore_stmt == false then cast_mode = CM_NO_RANGE_CHECK & CM_WARN_ON_FAIL ObCastMode cast_mode = is_strict_mode(expr_ctx.my_session_->get_sql_mode()) ? CM_NONE : CM_WARN_ON_FAIL; cast_mode = cast_mode | CM_COLUMN_CONVERT; if (expr_ctx.phy_plan_ctx_ != NULL && expr_ctx.phy_plan_ctx_->is_ignore_stmt()) { cast_mode = CM_WARN_ON_FAIL; } // do not worry too much about the efficiency here // gcc will construct and set column_conv_ctx_ directly // only one constructor call is necessary. no temporary object is created EXPR_DEFINE_CAST_CTX(expr_ctx, cast_mode); column_conv_ctx = cast_ctx; } return ret; } void ObSQLUtils::init_type_ctx(const ObSQLSessionInfo* session, ObExprTypeCtx& type_ctx) { if (NULL != session) { ObCollationType coll_type = CS_TYPE_INVALID; int64_t div_precision_increment = OB_INVALID_COUNT; int64_t ob_max_allowed_packet; if (share::is_mysql_mode()) { if (OB_SUCCESS == (session->get_collation_connection(coll_type))) { type_ctx.set_coll_type(coll_type); } } else if (share::is_oracle_mode()) { type_ctx.set_coll_type(session->get_nls_collation()); } if (OB_SUCCESS == (session->get_div_precision_increment(div_precision_increment))) { type_ctx.set_div_precision_increment(div_precision_increment); } if (OB_SUCCESS == (session->get_max_allowed_packet(ob_max_allowed_packet))) { type_ctx.set_max_allowed_packet(ob_max_allowed_packet); } CHECK_COMPATIBILITY_MODE(session); } else { LOG_WARN("Molly couldn't get compatibility mode from session, use default", K(lbt())); } type_ctx.set_session(session); } bool ObSQLUtils::use_px(const ObStmtHint& hint, bool dist_table /*true*/) { bool use_px = false; if (ObUsePxHint::ENABLE == hint.use_px_ && ObStmtHint::DEFAULT_PARALLEL < hint.parallel_) { use_px = true; } else if (ObUsePxHint::ENABLE == hint.use_px_ && (ObStmtHint::DEFAULT_PARALLEL == hint.parallel_ || ObStmtHint::UNSET_PARALLEL == hint.parallel_) && dist_table) { use_px = true; } else { use_px = false; } return use_px; } bool ObSQLUtils::is_oracle_sys_view(const ObString& table_name) { return table_name.prefix_match("ALL_") || table_name.prefix_match("USER_") || table_name.prefix_match("DBA_") || table_name.prefix_match("GV$") || table_name.prefix_match("V$") || 0 == table_name.compare("NLS_SESSION_PARAMETERS") || 0 == table_name.compare("NLS_INSTANCE_PARAMETERS") || 0 == table_name.compare("NLS_DATABASE_PARAMETERS") || 0 == table_name.compare("DICTIONARY") || 0 == table_name.compare("DICT") || 0 == table_name.compare("ROLE_TAB_PRIVS") || 0 == table_name.compare("ROLE_SYS_PRIVS") || 0 == table_name.compare("ROLE_ROLE_PRIVS"); } int ObSQLUtils::extend_checker_stmt(ObExecContext& ctx, uint64_t table_id, uint64_t ref_table_id, const common::ObIArray& part_ids, const bool is_weak) { int ret = OB_SUCCESS; if (!part_ids.empty()) { if (OB_FAIL( ObTableLocation::append_phy_table_location(ctx, table_id, ref_table_id, is_weak, part_ids, UNORDERED))) { LOG_WARN("append phy table location failed", K(ret)); } } return ret; } int ObSQLUtils::make_whole_range( ObIAllocator& allocator, const uint64_t ref_table_id, const int64_t rowkey_count, ObNewRange*& whole_range) { int ret = OB_SUCCESS; whole_range = NULL; ObNewRange* temp_range = NULL; if (OB_ISNULL(temp_range = static_cast(allocator.alloc(sizeof(ObNewRange))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory for query range failed"); } else if (OB_ISNULL(whole_range = new (temp_range) ObNewRange())) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to new whole range"); } else if (OB_FAIL(make_whole_range(allocator, ref_table_id, rowkey_count, *whole_range))) { LOG_WARN("Failed to make whole range inner", K(ret)); } return ret; } int ObSQLUtils::make_whole_range( ObIAllocator& allocator, const uint64_t ref_table_id, const int64_t rowkey_count, ObNewRange& whole_range) { int ret = OB_SUCCESS; ObObj* start_row_key = NULL; ObObj* end_row_key = NULL; if (OB_UNLIKELY(OB_INVALID_ID == ref_table_id) || OB_UNLIKELY(rowkey_count < 1)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ref_table_id), K(rowkey_count), K(ret)); } else if (OB_ISNULL(start_row_key = static_cast(allocator.alloc(sizeof(ObObj) * rowkey_count)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory for start_obj failed", K(ret)); } else if (OB_ISNULL(end_row_key = static_cast(allocator.alloc(sizeof(ObObj) * rowkey_count)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory for end_obj failed", K(ret)); } else { for (int i = 0; i < rowkey_count; ++i) { start_row_key[i] = ObRowkey::MIN_OBJECT; end_row_key[i] = ObRowkey::MAX_OBJECT; } whole_range.table_id_ = ref_table_id; whole_range.start_key_.assign(start_row_key, rowkey_count); whole_range.end_key_.assign(end_row_key, rowkey_count); whole_range.border_flag_.unset_inclusive_start(); whole_range.border_flag_.unset_inclusive_end(); } return ret; } ObAcsIndexInfo::~ObAcsIndexInfo() { if (NULL != allocator_) { if (NULL != query_range_) { query_range_->~ObQueryRange(); allocator_->free(query_range_); query_range_ = NULL; } if (NULL != index_name_.ptr()) { allocator_->free(index_name_.ptr()); index_name_.reset(); } } }; int ObAcsIndexInfo::deep_copy(const ObAcsIndexInfo& other) { int ret = OB_SUCCESS; index_id_ = other.index_id_; is_whole_range_ = other.is_whole_range_; is_index_back_ = other.is_index_back_; prefix_filter_sel_ = other.prefix_filter_sel_; query_range_ = NULL; if (OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(allocator_), K(ret)); } else if (OB_FAIL(column_id_.init(other.column_id_.count()))) { LOG_WARN("failed to init fixed array", K(ret)); } else if (OB_FAIL(column_id_.assign(other.column_id_))) { LOG_WARN("failed to assign column id", K(ret)); } else if (OB_FAIL(ob_write_string(*allocator_, other.index_name_, index_name_))) { LOG_WARN("failed to copy index name", K(ret)); } else { // deep copy query range if (NULL != other.query_range_) { ObQueryRange* temp_query_range = static_cast(allocator_->alloc(sizeof(ObQueryRange))); if (OB_ISNULL(temp_query_range)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory for query range"); } else { temp_query_range = new (temp_query_range) ObQueryRange(); if (OB_FAIL(temp_query_range->deep_copy(*other.query_range_))) { temp_query_range->~ObQueryRange(); query_range_ = NULL; } else { query_range_ = temp_query_range; } } } } return ret; } int ObSQLUtils::ConvertFiledNameAttribute( ObIAllocator& allocator, const ObString& src, ObString& dst, const uint16_t collation_type) { int ret = OB_SUCCESS; const ObCollationType cs_type = static_cast(collation_type); if (CHARSET_UTF8MB4 == ObCharset::charset_type_by_coll(cs_type) || CS_TYPE_BINARY == cs_type || CS_TYPE_INVALID == cs_type) { OZ(ob_write_string(allocator, src, dst)); } else { char* buf = nullptr; const int32_t CharConvertFactorNum = 2; int32_t buf_len = src.length() * CharConvertFactorNum; uint32_t result_len = 0; const ObCollationType from_collation = ObCharset::get_default_collation(ObCharset::get_default_charset()); const ObCollationType to_collation = static_cast(collation_type); if (OB_ISNULL(src.ptr()) || OB_UNLIKELY(0 >= src.length())) { dst.assign(NULL, 0); } else if (nullptr == (buf = static_cast(allocator.alloc(buf_len)))) { dst.assign(NULL, 0); ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("allocate memory failed", K(ret), "len", buf_len); } else { ret = ObCharset::charset_convert(from_collation, src.ptr(), src.length(), to_collation, buf, buf_len, result_len); if (OB_SUCCESS != ret) { int32_t str_offset = 0; int64_t buf_offset = 0; ObString question_mark = ObCharsetUtils::get_const_str(to_collation, '?'); while (str_offset < src.length() && buf_offset + question_mark.length() <= buf_len) { int64_t offset = ObCharset::charpos(from_collation, src.ptr() + str_offset, src.length() - str_offset, 1); ret = ObCharset::charset_convert(from_collation, src.ptr() + str_offset, offset, to_collation, buf + buf_offset, buf_len - buf_offset, result_len); str_offset += offset; if (OB_SUCCESS == ret) { buf_offset += result_len; } else { MEMCPY(buf + buf_offset, question_mark.ptr(), question_mark.length()); buf_offset += question_mark.length(); } } if (str_offset < src.length()) { ret = OB_SIZE_OVERFLOW; LOG_WARN("size overflow", K(ret), K(src), KPHEX(src.ptr(), src.length())); } else { result_len = buf_offset; ret = OB_SUCCESS; LOG_WARN("charset convert failed", K(ret), K(from_collation), K(to_collation)); } } if (OB_SUCC(ret)) { dst.assign(buf, result_len); } } } return ret; } int ObSQLUtils::clear_evaluated_flag(const ObExprPtrIArray& calc_exprs, ObEvalCtx& eval_ctx) { int ret = OB_SUCCESS; for (int i = 0; OB_SUCC(ret) && i < calc_exprs.count(); i++) { if (OB_ISNULL(calc_exprs.at(i))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(calc_exprs), K(i)); } else { calc_exprs.at(i)->get_eval_info(eval_ctx).clear_evaluated_flag(); } } return ret; } int ObSQLUtils::copy_and_convert_string_charset( ObIAllocator& allocator, const ObString& src, ObString& dst, ObCollationType src_coll, ObCollationType dst_coll) { return ObCharset::charset_convert(allocator, src, src_coll, dst_coll, dst, ObCharset::COPY_STRING_ON_SAME_CHARSET); } int ObSQLUtils::update_session_last_schema_version( ObMultiVersionSchemaService& schema_service, ObSQLSessionInfo& session_info) { int ret = OB_SUCCESS; int64_t received_schema_version = OB_INVALID_VERSION; uint64_t tenant_id = session_info.get_effective_tenant_id(); if (OB_FAIL(schema_service.get_tenant_received_broadcast_version(tenant_id, received_schema_version))) { LOG_WARN("fail to get tenant received brocast version", K(ret), K(tenant_id)); } else if (OB_FAIL(session_info.update_sys_variable(SYS_VAR_OB_LAST_SCHEMA_VERSION, received_schema_version))) { LOG_WARN("fail to set session variable for last_schema_version", K(ret)); } return ret; } OB_SERIALIZE_MEMBER( ObImplicitCursorInfo, stmt_id_, affected_rows_, found_rows_, matched_rows_, duplicated_rows_, deleted_rows_); int ObImplicitCursorInfo::merge_cursor(const ObImplicitCursorInfo& other) { int ret = OB_SUCCESS; if (OB_INVALID_INDEX == stmt_id_) { // not init, init it with first cursor info *this = other; } else if (stmt_id_ != other.stmt_id_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt_id is different", K(stmt_id_), K(other.stmt_id_)); } else { affected_rows_ += other.affected_rows_; found_rows_ += other.found_rows_; matched_rows_ += other.matched_rows_; duplicated_rows_ += other.duplicated_rows_; deleted_rows_ += other.deleted_rows_; } return ret; } OB_SERIALIZE_MEMBER(ObParamPosIdx, pos_, idx_); int ObLinkStmtParam::write(char* buf, int64_t buf_len, int64_t& pos, int64_t param_idx) { /* * we need 4 bytes for every const param: * 1 byte: '\0' for meta info flag. '\0' can not appear in any sql stmt fmt. * 1 byte: meta info type. now we used 0 to indicate const param. * 2 bytes: uint16 for param index. */ int ret = OB_SUCCESS; if (buf_len - pos < PARAM_LEN) { ret = OB_BUF_NOT_ENOUGH; LOG_WARN("buffer is not enough", K(ret), K(buf_len), K(pos)); } else if (param_idx < 0 || param_idx > UINT16_MAX) { ret = OB_NOT_SUPPORTED; LOG_WARN("param count should be between 0 and UINT16_MAX", K(ret), K(param_idx)); } else { buf[pos++] = 0; // meta flag. buf[pos++] = 0; // meta type. *(uint16_t*)(buf + pos) = param_idx; pos += sizeof(uint16_t); } return ret; } int ObLinkStmtParam::read_next(const char* buf, int64_t buf_len, int64_t& pos, int64_t& param_idx) { int ret = OB_SUCCESS; const char* ch = buf + pos; const char* buf_end = buf + buf_len - PARAM_LEN + 1; param_idx = -1; while (OB_SUCC(ret) && param_idx < 0 && ch < buf_end) { if (0 != ch[0]) { ch++; } else if (0 != ch[1]) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unknown meta type", "meta_type", static_cast(ch[1])); } else { param_idx = static_cast(*(uint16_t*)(ch + 2)); } } pos = ch - buf; return ret; } int64_t ObLinkStmtParam::get_param_len() { return PARAM_LEN; } const int64_t ObLinkStmtParam::PARAM_LEN = sizeof(char) * 2 + sizeof(uint16_t); bool ObSQLUtils::is_same_type_for_compare(const ObObjMeta& meta1, const ObObjMeta& meta2) { bool is_same = false; if (meta1.get_type() == meta2.get_type()) { is_same = true; if (meta1.is_string_type()) { is_same = meta1.get_collation_type() == meta2.get_collation_type(); } } LOG_DEBUG("is same type for compare", K(meta1), K(meta2), K(is_same), K(lbt())); return is_same; } int ObSQLUtils::generate_new_name_with_escape_character( common::ObIAllocator& allocator, const ObString& src, ObString& dst, bool is_oracle_mode) { int ret = OB_SUCCESS; const ObString::obstr_size_t src_len = src.length(); ObString::obstr_size_t dst_len = src_len; const char escape_character = is_oracle_mode ? '"' : '`'; char* ptr = NULL; if (OB_ISNULL(src.ptr()) || OB_UNLIKELY(0 >= src_len)) { dst.assign(NULL, 0); } else if (NULL == src.find(escape_character)) { dst = src; } else { for (int64_t i = 0; i < src_len; ++i) { if (src[i] == escape_character) { ++dst_len; } } if (NULL == (ptr = static_cast(allocator.alloc(dst_len + 1)))) { dst = NULL; ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("allocate memory failed", K(ret), "size", dst_len); } else { int64_t tmp_dst_pos = 0; for (int64_t i = 0; i < src_len; i++) { if (src[i] == escape_character) { ptr[tmp_dst_pos++] = escape_character; ptr[tmp_dst_pos++] = escape_character; } else { ptr[tmp_dst_pos++] = src[i]; } } if (tmp_dst_pos != dst_len) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dst_len is not equal to tmp_dst_pos", K(ret), K(tmp_dst_pos), K(dst_len)); } else { ptr[dst_len] = '\0'; dst.assign_ptr(ptr, dst_len); } } } return ret; } int ObVirtualTableResultConverter::reset_and_init(ObIAllocator* key_alloc, sql::ObSQLSessionInfo* session, const common::ObIArray* output_row_types, const common::ObIArray* key_types, const common::ObIArray* key_with_tenant_ids, const common::ObIArray* extra_tenant_id, ObIAllocator* init_alloc, const share::schema::ObTableSchema* table_schema, const common::ObIArray* output_column_ids, const bool use_real_tenant_id, const bool has_tenant_id_col, const int64_t max_col_cnt /* INT64_MAX */) { int ret = OB_SUCCESS; if (OB_NOT_NULL(key_alloc)) { // like reset key_cast_ctx_ = *(new (reinterpret_cast(&key_cast_ctx_)) ObCastCtx()); output_row_cast_ctx_ = *(new (reinterpret_cast(&output_row_cast_ctx_)) ObCastCtx()); key_alloc_ = nullptr; output_row_types_ = nullptr; key_types_ = nullptr; key_with_tenant_ids_ = nullptr; has_extra_tenant_ids_ = nullptr; table_schema_ = nullptr; output_column_ids_ = nullptr; base_table_id_ = UINT64_MAX; cur_tenant_id_ = UINT64_MAX; output_row_alloc_.reuse(); } if (OB_ISNULL(key_alloc) || OB_ISNULL(init_alloc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("allocator is null", K(ret), KP(key_alloc), KP(init_alloc)); } else if (OB_NOT_NULL(key_with_tenant_ids) && key_with_tenant_ids->count() != key_types->count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("the count of column type and extra tenant id is not match", K(ret), K(key_with_tenant_ids->count()), K(key_types->count())); } else if (output_column_ids->count() != output_row_types->count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("the count of column type and extra tenant id is not match", K(ret), K(output_column_ids->count()), K(output_row_types->count())); } else { key_alloc_ = key_alloc; if (OB_ISNULL(init_alloc_)) { init_alloc_ = init_alloc; } output_row_types_ = output_row_types; key_types_ = key_types; max_col_cnt_ = max_col_cnt; key_with_tenant_ids_ = key_with_tenant_ids; has_extra_tenant_ids_ = extra_tenant_id; use_real_tenant_id_ = use_real_tenant_id; has_tenant_id_col_ = has_tenant_id_col; table_schema_ = table_schema; output_column_ids_ = output_column_ids; base_table_id_ = table_schema->get_table_id(); cur_tenant_id_ = table_schema->get_tenant_id(); // calc collation ObCollationType cs_type = ObCharset::get_system_collation(); for (int64_t i = 0; i < output_row_types->count() && OB_SUCC(ret); ++i) { const ObObjMeta& obj_meta = output_row_types->at(i); if (ob_is_string_tc(obj_meta.get_type())) { cs_type = obj_meta.get_collation_type(); break; } } ObCollationType key_cs_type = ObCharset::get_system_collation(); for (int64_t i = 0; i < key_types->count() && OB_SUCC(ret); ++i) { const ObObjMeta& obj_meta = key_types->at(i); if (ob_is_string_tc(obj_meta.get_type())) { key_cs_type = obj_meta.get_collation_type(); break; } } { CompatModeGuard g(ObWorker::CompatMode::MYSQL); const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(session); key_cast_ctx_ = *(new (reinterpret_cast(&key_cast_ctx_)) ObCastCtx(key_alloc, &dtc_params, CM_NONE, key_cs_type)); } // for output row to convert const ObDataTypeCastParams dtc_params2 = ObBasicSessionInfo::create_dtc_params(session); output_row_cast_ctx_ = *(new (reinterpret_cast(&output_row_cast_ctx_)) ObCastCtx(&output_row_alloc_, &dtc_params2, CM_NONE, cs_type)); if (0 == cols_schema_.count() && OB_FAIL(get_all_columns_schema())) { LOG_WARN("fail to get column schema", K(ret)); } LOG_DEBUG("debug init converter", K(cs_type)); } return ret; } int ObVirtualTableResultConverter::init_without_allocator( const common::ObIArray& col_schemas, const common::ObIArray* extra_tenant_ids, uint64_t cur_tenant_id, uint64_t tenant_id_col_id, const bool use_real_tenant_id) { int ret = OB_SUCCESS; has_extra_tenant_ids_ = extra_tenant_ids; cur_tenant_id_ = cur_tenant_id; tenant_id_col_id_ = tenant_id_col_id; use_real_tenant_id_ = use_real_tenant_id; ObTZMapWrap tz_map_wrap; if (0 < cols_schema_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cols schema is not empty", K(ret)); } else if (OB_FAIL(cols_schema_.assign(col_schemas))) { LOG_WARN("failed to assign column schema", K(ret)); } else if (OB_FAIL(OTTZ_MGR.get_tenant_tz(cur_tenant_id_, tz_map_wrap))) { LOG_WARN("get tenant timezone map failed", K(ret)); } else { int ret_more = OB_SUCCESS; int32_t offset_sec = 0; tz_info_wrap_.set_tz_info_map(tz_map_wrap.get_tz_map()); if (OB_FAIL(ObTimeConverter::str_to_offset("+8:00", offset_sec, ret_more, true))) { if (ret != OB_ERR_UNKNOWN_TIME_ZONE) { LOG_WARN("fail to convert str_to_offset", K(ret)); } else if (ret_more != OB_SUCCESS) { ret = ret_more; LOG_WARN("invalid time zone hour or minute", K(ret)); } } else { tz_info_wrap_.set_tz_info_offset(offset_sec); } } // set cat params ObString session_nls_formats[ObNLSFormatEnum::NLS_MAX]; session_nls_formats[ObNLSFormatEnum::NLS_DATE] = ObTimeConverter::COMPAT_OLD_NLS_DATE_FORMAT; session_nls_formats[ObNLSFormatEnum::NLS_TIMESTAMP] = ObTimeConverter::COMPAT_OLD_NLS_TIMESTAMP_FORMAT; session_nls_formats[ObNLSFormatEnum::NLS_TIMESTAMP_TZ] = ObTimeConverter::DEFAULT_NLS_TIMESTAMP_TZ_FORMAT; ObDataTypeCastParams dtc_params2 = ObDataTypeCastParams(tz_info_wrap_.get_time_zone_info(), session_nls_formats, col_schemas.at(0)->get_collation_type(), col_schemas.at(0)->get_collation_type(), CS_TYPE_UTF8MB4_BIN); output_row_cast_ctx_ = *(new (reinterpret_cast(&output_row_cast_ctx_)) ObCastCtx(&output_row_alloc_, &dtc_params2, CM_NONE, ObCharset::get_system_collation())); LOG_DEBUG("debug timezone", K(tz_info_wrap_.get_time_zone_info()), K(ret)); return ret; } void ObVirtualTableResultConverter::destroy() { key_cast_ctx_ = *(new (reinterpret_cast(&key_cast_ctx_)) ObCastCtx()); output_row_cast_ctx_ = *(new (reinterpret_cast(&output_row_cast_ctx_)) ObCastCtx()); output_row_types_ = nullptr; key_types_ = nullptr; has_extra_tenant_ids_ = nullptr; inited_row_ = false; if (OB_NOT_NULL(convert_row_.cells_)) { if (OB_NOT_NULL(init_alloc_)) { init_alloc_->free(convert_row_.cells_); } convert_row_.cells_ = nullptr; } convert_row_.count_ = 0; base_table_id_ = UINT64_MAX; cur_tenant_id_ = UINT64_MAX; table_schema_ = nullptr; output_column_ids_ = nullptr; cols_schema_.reset(); output_row_alloc_.reset(); key_alloc_ = nullptr; init_alloc_ = nullptr; } int ObVirtualTableResultConverter::get_need_convert_key_ranges_pos(ObNewRange& key_range, int64_t& pos) { int ret = OB_SUCCESS; pos = INT64_MAX; const ObRowkey& start_key = key_range.start_key_; const ObRowkey& end_key = key_range.end_key_; if (start_key.get_obj_cnt() != end_key.get_obj_cnt()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("start key is not match with end key", K(ret), "start key cnt", start_key.get_obj_cnt(), "end key cnt", end_key.get_obj_cnt()); } else if (start_key.get_obj_cnt() > 0) { const ObObj* start_key_objs = start_key.get_obj_ptr(); const ObObj* end_key_objs = end_key.get_obj_ptr(); for (uint64_t nth_obj = 0; OB_SUCC(ret) && nth_obj < start_key.get_obj_cnt(); ++nth_obj) { if ((start_key_objs[nth_obj].is_ext() || start_key_objs[nth_obj].is_null()) && !end_key_objs[nth_obj].is_ext()) { pos = nth_obj; break; } else if ((end_key_objs[nth_obj].is_ext() || end_key_objs[nth_obj].is_null()) && !start_key_objs[nth_obj].is_ext()) { pos = nth_obj; break; } } } return ret; } int ObVirtualTableResultConverter::convert_key_ranges(ObIArray& key_ranges) { int ret = OB_SUCCESS; if (!key_ranges.empty()) { common::ObArray tmp_range; OZ(tmp_range.reserve(key_ranges.count())); CK(OB_NOT_NULL(key_types_)); for (int64_t i = 0; OB_SUCC(ret) && i < key_ranges.count(); ++i) { ObNewRange new_range; new_range.table_id_ = key_ranges.at(i).table_id_; new_range.border_flag_ = key_ranges.at(i).border_flag_; int64_t pos = INT64_MAX; if (OB_FAIL(get_need_convert_key_ranges_pos(key_ranges.at(i), pos))) { LOG_WARN("failed to get convert key range pos", K(ret)); } else if (OB_FAIL(convert_key(key_ranges.at(i).start_key_, new_range.start_key_, true, pos))) { LOG_WARN("fail to convert start key", K(ret)); } else if (OB_FAIL(convert_key(key_ranges.at(i).end_key_, new_range.end_key_, false, pos))) { LOG_WARN("fail to convert end key", K(ret)); } else if (OB_FAIL(tmp_range.push_back(new_range))) { LOG_WARN("fail to push back new range", K(ret)); } } // end for if (OB_SUCC(ret)) { key_ranges.reset(); if (OB_FAIL(key_ranges.assign(tmp_range))) { LOG_WARN("fail to assign new range", K(ret)); } } } return ret; } int ObVirtualTableResultConverter::get_all_columns_schema() { int ret = OB_SUCCESS; if (OB_ISNULL(table_schema_) || OB_ISNULL(output_column_ids_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table schema is null or output columns ids is null", K(ret)); } else if (0 < output_column_ids_->count() && OB_FAIL(cols_schema_.reserve(output_column_ids_->count()))) { LOG_WARN("failed to reserve output columns ids", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < output_column_ids_->count(); ++i) { const uint64_t column_id = output_column_ids_->at(i); const ObColumnSchemaV2* col_schema = table_schema_->get_column_schema(column_id); if (OB_ISNULL(col_schema)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("col_schema is NULL", K(ret), K(column_id)); } else if (OB_FAIL(cols_schema_.push_back(col_schema))) { LOG_WARN("failed to push back column schema", K(ret)); } else if (0 == col_schema->get_column_name_str().case_compare("TENANT_ID")) { if (UINT64_MAX != tenant_id_col_id_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("init twice tenant id col id", K(ret), K(tenant_id_col_id_), K(column_id)); } tenant_id_col_id_ = column_id; } else { LOG_TRACE("trace column type", K(col_schema->get_data_type()), K(col_schema->get_collation_type())); } } return ret; } int ObVirtualTableResultConverter::init_output_row(int64_t cell_cnt) { int ret = OB_SUCCESS; void* tmp_ptr = nullptr; ObObj* cells = NULL; const int64_t max_cell_cnt = INT64_MAX != max_col_cnt_ ? max_col_cnt_ : cell_cnt; if (max_col_cnt_ < cell_cnt) { ret = OB_ERR_UNEXPECTED; LOG_WARN("max col cnt is less than cell cnt", K(ret), K(max_cell_cnt), K(cell_cnt)); } else if (OB_ISNULL(tmp_ptr = init_alloc_->alloc(max_cell_cnt * sizeof(ObObj)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc cells", K(ret), K(max_cell_cnt), K(cell_cnt)); } else if (OB_ISNULL(cells = new (tmp_ptr) ObObj[max_cell_cnt])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to new cell array", K(ret), K(max_cell_cnt)); } else { convert_row_.cells_ = cells; convert_row_.count_ = cell_cnt; inited_row_ = true; LOG_DEBUG("debug output row", K(cell_cnt), K(max_col_cnt_)); } return ret; } int ObVirtualTableResultConverter::convert_output_row(ObNewRow*& src_row) { int ret = OB_SUCCESS; if (OB_ISNULL(src_row)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("current row is NULL", K(ret)); } else if (!inited_row_ && OB_FAIL(init_output_row(src_row->count_))) { LOG_WARN("failed to init row"); } else if (output_column_ids_->count() != src_row->count_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected status: src row and dst row is not match", K(ret), K(src_row->count_), K(output_column_ids_->count())); } else { output_row_alloc_.reuse(); for (int64_t i = 0; OB_SUCC(ret) && i < output_column_ids_->count(); ++i) { bool need_cast = true; const uint64_t column_id = output_column_ids_->at(i); const ObObjMeta& obj_meta = output_row_types_->at(i); ObObj src_obj = src_row->get_cell(i); if (tenant_id_col_id_ == column_id) { src_obj.set_uint64(cur_tenant_id_); } else if (src_row->get_cell(i).is_string_type() && 0 == src_row->get_cell(i).get_data_length()) { need_cast = false; convert_row_.cells_[i].set_null(); } else if (nullptr != has_extra_tenant_ids_ && need_process_tenant_id(i, src_obj) && OB_FAIL(process_tenant_id(has_extra_tenant_ids_, i, output_row_alloc_, false, src_obj))) { // extra tenant id LOG_WARN("failed to process tenant id", K(ret)); } LOG_DEBUG("debug type", K(obj_meta.get_type()), K(obj_meta.get_collation_type()), K(src_obj), K(convert_row_.cells_[i])); if (OB_FAIL(ret)) { } else if (need_cast) { if (OB_FAIL(ObObjCaster::to_type(obj_meta.get_type(), obj_meta.get_collation_type(), output_row_cast_ctx_, src_obj, convert_row_.cells_[i]))) { LOG_WARN("failed to cast obj in oracle mode", K(ret), K(column_id)); } else { LOG_DEBUG("debug type", K(obj_meta.get_type()), K(obj_meta.get_collation_type()), K(src_obj), K(convert_row_.cells_[i]), K(output_row_cast_ctx_.dest_collation_)); } } } src_row = &convert_row_; } return ret; } // only for stat collect int ObVirtualTableResultConverter::convert_column(ObObj& src_obj, uint64_t column_id, uint64_t idx) { int ret = OB_SUCCESS; if (idx >= cols_schema_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column idx is invalid", K(idx), K(cols_schema_.count())); } else { ObObj dst_obj = src_obj; bool need_cast = true; const ObColumnSchemaV2* col_schema = cols_schema_.at(idx); if (col_schema->get_column_id() != column_id) { ret = OB_ERR_UNEXPECTED; LOG_WARN("column is not match", K(ret), K(column_id), K(col_schema->get_column_id())); } else if (tenant_id_col_id_ == column_id) { dst_obj.set_uint64(cur_tenant_id_); } else if (src_obj.is_null() || (src_obj.is_string_type() && 0 == src_obj.get_data_length())) { need_cast = false; src_obj.set_null(); } else if (src_obj.is_ext()) { need_cast = false; } else if (nullptr != key_with_tenant_ids_ && need_process_tenant_id(idx, dst_obj) && OB_FAIL(process_tenant_id(key_with_tenant_ids_, idx, output_row_alloc_, false, dst_obj))) { // extra tenant id LOG_WARN("failed to process tenant id", K(ret)); } if (OB_FAIL(ret)) { } else if (need_cast && OB_FAIL(ObObjCaster::to_type(col_schema->get_data_type(), col_schema->get_collation_type(), output_row_cast_ctx_, dst_obj, src_obj))) { LOG_WARN("failed to cast obj in oracle mode", K(ret), K(idx), K(column_id)); } else { LOG_DEBUG("debug convert column", K(src_obj), K(column_id), K(idx)); } } return ret; } bool ObVirtualTableResultConverter::need_process_tenant_id(int64_t nth_col, ObObj& obj) { bool needed = false; if (!has_extra_tenant_ids_->at(nth_col) || obj.is_null()) { // do nothing } else if (OB_SYS_TENANT_ID == cur_tenant_id_ && OB_ALL_SEQUENCE_VALUE_TID != extract_pure_id(base_table_id_)) { // __all_sequence_value's sequence_id always filter tenant_id } else if ((OB_ALL_ROUTINE_PARAM_TID == extract_pure_id(base_table_id_) || OB_ALL_ROUTINE_PARAM_HISTORY_TID == extract_pure_id(base_table_id_)) && 0 == cols_schema_.at(nth_col)->get_column_name_str().case_compare("type_owner") && obj.is_int() && obj.get_int() > 0 && OB_SYS_TENANT_ID == extract_tenant_id(obj.get_int())) { // tenant_id of __all_routine_param's type_owner may be OB_SYS_TENANT_ID, do not filter it. } else if (OB_ALL_TENANT_DEPENDENCY_TID == extract_pure_id(base_table_id_) && (0 == cols_schema_.at(nth_col)->get_column_name_str().case_compare("ref_obj_id") && obj.is_int() && obj.get_int() > 0) && OB_SYS_TENANT_ID == extract_tenant_id(obj.get_int())) { // ref_obj_id may contain sys tenant id, do not filter it. } else if ((OB_ALL_TYPE_ATTR_TID == extract_pure_id(base_table_id_) || OB_ALL_TYPE_ATTR_HISTORY_TID == extract_pure_id(base_table_id_)) && 0 == cols_schema_.at(nth_col)->get_column_name_str().case_compare("type_attr_id") && obj.is_int() && obj.get_int() > 0 && OB_SYS_TENANT_ID == extract_tenant_id(obj.get_int())) { // tenant_id of __all_type_attr's type_attr_id may be OB_SYS_TENANT_ID, do not filter it. } else if ((OB_ALL_COLL_TYPE_TID == extract_pure_id(base_table_id_) || OB_ALL_COLL_TYPE_HISTORY_TID == extract_pure_id(base_table_id_)) && 0 == cols_schema_.at(nth_col)->get_column_name_str().case_compare("elem_type_id") && obj.is_int() && obj.get_int() > 0 && OB_SYS_TENANT_ID == extract_tenant_id(obj.get_int())) { // tenant_id of __all_coll_type's elem_type_id may be OB_SYS_TENANT_ID, do not filter it. } else { needed = true; } return needed; } int ObVirtualTableResultConverter::convert_output_row( ObEvalCtx& eval_ctx, const common::ObIArray& src_exprs, const common::ObIArray& dst_exprs) { int ret = OB_SUCCESS; if (!inited_row_ && OB_FAIL(init_output_row(dst_exprs.count()))) { LOG_WARN("failed to init row"); } else if (dst_exprs.count() != dst_exprs.count() || output_column_ids_->count() != dst_exprs.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected status: src row and dst row is not match", K(ret), K(dst_exprs.count())); } else { output_row_alloc_.reuse(); for (int64_t i = 0; OB_SUCC(ret) && i < output_column_ids_->count(); ++i) { const uint64_t column_id = output_column_ids_->at(i); const ObObjMeta& obj_meta = output_row_types_->at(i); ObDatum* datum = nullptr; ObExpr* expr = src_exprs.at(i); ObExpr* dst_expr = dst_exprs.at(i); ObDatum& dst_datum = dst_expr->locate_datum_for_write(eval_ctx); ObObj dst_obj; if (tenant_id_col_id_ == column_id) { convert_row_.cells_[i].set_uint64(cur_tenant_id_); } else if (OB_FAIL(expr->eval(eval_ctx, datum))) { LOG_WARN("failed to eval datum", K(ret)); } else if (OB_FAIL(datum->to_obj(convert_row_.cells_[i], expr->obj_meta_))) { LOG_WARN("failed to cast obj", K(ret)); } else if (convert_row_.cells_[i].is_null() || (convert_row_.cells_[i].is_string_type() && 0 == convert_row_.cells_[i].get_data_length())) { convert_row_.cells_[i].set_null(); } else if (nullptr != has_extra_tenant_ids_ && need_process_tenant_id(i, convert_row_.cells_[i]) && OB_FAIL( process_tenant_id(has_extra_tenant_ids_, i, output_row_alloc_, false, convert_row_.cells_[i]))) { // extra tenant id LOG_WARN("failed to process tenant id", K(ret)); } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObObjCaster::to_type(obj_meta.get_type(), obj_meta.get_collation_type(), output_row_cast_ctx_, convert_row_.cells_[i], dst_obj))) { LOG_WARN("failed to cast obj in oracle mode", K(ret), K(column_id)); } else if (OB_FAIL(dst_datum.from_obj(dst_obj))) { LOG_WARN("failed to cast obj", K(ret)); } else { dst_expr->get_eval_info(eval_ctx).evaluated_ = true; } } } return ret; } int ObVirtualTableResultConverter::convert_key(const ObRowkey& src, ObRowkey& dst, bool is_start_key, int64_t pos) { int ret = OB_SUCCESS; UNUSED(is_start_key); if (src.get_obj_cnt() > 0) { const ObObj* src_key_objs = src.get_obj_ptr(); void* tmp_ptr = NULL; ObObj* new_key_obj = NULL; tmp_ptr = key_alloc_->alloc(src.get_obj_cnt() * sizeof(ObObj)); if (OB_ISNULL(tmp_ptr)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc new obj", K(ret)); } else if (OB_ISNULL(new_key_obj = new (tmp_ptr) ObObj[src.get_obj_cnt()])) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc new obj", K(ret)); } else if (src.get_obj_cnt() != key_types_->count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("keys are not match with columns", K(ret)); } CompatModeGuard g(ObWorker::CompatMode::MYSQL); for (int64_t nth_obj = 0; OB_SUCC(ret) && nth_obj < src.get_obj_cnt(); ++nth_obj) { const ObObj& src_obj = src_key_objs[nth_obj]; if (pos == nth_obj && (src_obj.is_ext() || src_obj.is_null())) { /** * explain extended select * from t1 where c1<1; mysql: range(NULL,MAX,MAX ; 1,MIN,MIN) oracle:range(MIN,MIN,MIN ; 1,MIN,MIN) explain extended select * from t1 where c1<=1; mysql:range(NULL,MAX,MAX ; 1,MAX,MAX) oracle:range(MIN,MIN,MIN ; 1,MAX,MAX) explain extended select * from t1 where c1>1; mysql:range(1,MAX,MAX ; MAX,MAX,MAX) oracle:range(1,MAX,MAX ; NULL,MIN,MIN) explain extended select * from t1 where c1>=1; mysql:range(1,MIN,MIN ; MAX,MAX,MAX) oracle:range(1,MIN,MIN ; NULL,MIN,MIN) explain extended select * from t1 where c1=1 and c2<1; mysql:range(1,NULL,MAX ; 1,1,MIN) oracle:range(1,MIN,MIN ; 1,1,MIN) **/ if (is_start_key) { if (src_obj.is_min_value()) { for (int64_t null_pos = nth_obj; null_pos < src.get_obj_cnt() && OB_SUCC(ret); ++null_pos) { if (src_key_objs[null_pos].is_min_value()) { if (null_pos == nth_obj) { new_key_obj[nth_obj].set_null(); } else { new_key_obj[nth_obj].set_max_value(); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected status: start key range is invalid", K(ret), K(src)); } } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected status: start key range is invalid", K(ret), K(src)); } } else { if (src_obj.is_null()) { for (int64_t null_pos = nth_obj; null_pos < src.get_obj_cnt() && OB_SUCC(ret); ++null_pos) { if (src_key_objs[null_pos].is_null()) { if (pos != nth_obj) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected status: end key range is invalid", K(ret), K(src)); } else { new_key_obj[nth_obj].set_max_value(); } } else if (src_key_objs[null_pos].is_min_value()) { new_key_obj[nth_obj].set_max_value(); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected status: end key range is invalid", K(ret), K(src)); } } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected status: end key range is invalid", K(ret), K(src)); } } break; } else if (src_obj.is_min_value()) { new_key_obj[nth_obj].set_min_value(); } else if (src_obj.is_max_value()) { new_key_obj[nth_obj].set_max_value(); } else if (src_obj.is_null()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected key range", K(src), K(ret)); } else { const ObObjMeta& obj_meta = key_types_->at(nth_obj); if (OB_FAIL(ObObjCaster::to_type(obj_meta.get_type(), obj_meta.get_collation_type(), key_cast_ctx_, src_key_objs[nth_obj], new_key_obj[nth_obj]))) { LOG_WARN("fail to cast obj", K(ret), K(key_types_->at(nth_obj)), K(src_key_objs[nth_obj])); } else if (OB_FAIL(process_tenant_id(key_with_tenant_ids_, nth_obj, *key_alloc_, true, new_key_obj[nth_obj]))) { // extra tenant id LOG_WARN("failed to process tenant id", K(ret)); } else if (has_tenant_id_col_ && 0 == nth_obj && !use_real_tenant_id_) { if (new_key_obj[nth_obj].get_type() == ObIntType) { new_key_obj[nth_obj].set_int(new_key_obj[nth_obj].get_int() - cur_tenant_id_); } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected tenant id type", K(new_key_obj[nth_obj].get_type()), K(ret)); } } } } // end for if (OB_SUCC(ret)) { LOG_TRACE("trace range key", K(ret), K(new_key_obj[0]), K(tenant_id_col_id_), K(use_real_tenant_id_)); dst.assign(new_key_obj, src.get_obj_cnt()); } } return ret; } int ObVirtualTableResultConverter::process_tenant_id(const ObIArray* extract_tenant_ids, const int64_t nth_col, ObIAllocator& allocator, bool is_extra_tenant_id, ObObj& obj) { int ret = OB_SUCCESS; if (OB_ISNULL(extract_tenant_ids) || !extract_tenant_ids->at(nth_col) || obj.is_null()) { } else if (!obj.is_int() && !obj.is_uint64() && !obj.is_varchar_or_char()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("not supported obj type", K(ret), K(obj)); } else if (obj.is_int() && obj.get_int() > 0) { int64_t value = is_extra_tenant_id ? extract_pure_id(obj.get_int()) : static_cast(combine_id(cur_tenant_id_, obj.get_int())); obj.set_int_value(value); } else if (obj.is_uint64() && 0 != obj.get_uint64()) { uint64_t value = is_extra_tenant_id ? static_cast(extract_pure_id(obj.get_int())) : combine_id(cur_tenant_id_, obj.get_int()); obj.set_uint64_value(value); } else if (obj.is_varchar_or_char()) { // __all_sys_stat column `value` int64_t value = OB_INVALID_ID; if (OB_FAIL(ObSchemaUtils::str_to_int(obj.get_string(), value))) { LOG_WARN("fail to covert str to int", K(ret), K(obj)); } else if (value > 0) { value = is_extra_tenant_id ? extract_pure_id(value) : static_cast(combine_id(cur_tenant_id_, value)); int64_t len = OB_MAX_BIT_LENGTH; char* buf = static_cast(allocator.alloc(len)); int64_t pos = 0; if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc memory failed", K(ret)); } else if (OB_FAIL(databuff_printf(buf, len, pos, "%lu", value))) { LOG_WARN("fail to convert uint to str", K(ret), K(value)); } else if (0 == pos || pos >= len) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid pos", K(ret), K(pos)); } else { obj.set_char_value(buf, static_cast(pos)); } } } LOG_DEBUG("debug extra tenant id", K(obj)); return ret; } int ObSQLUtils::check_table_version( bool& equal, const DependenyTableStore& dependency_tables, share::schema::ObSchemaGetterGuard& schema_guard) { int ret = OB_SUCCESS; equal = true; int64_t latest_table_version = -1; for (int64_t i = 0; i < dependency_tables.count(); i++) { const share::schema::ObSchemaObjVersion& table_version = dependency_tables.at(i); if (OB_FAIL(schema_guard.get_table_schema_version(table_version.get_object_id(), latest_table_version))) { LOG_WARN("failed to get table schema version", K(ret), K(table_version.get_object_id())); } if (table_version.get_version() != latest_table_version) { equal = false; } } return ret; } int ObSQLUtils::generate_view_definition_for_resolve(ObIAllocator& allocator, ObCollationType connection_collation, const ObViewSchema& view_schema, ObString& view_definition) { int ret = OB_SUCCESS; const ObString raw_view_def = view_schema.get_view_definition_str(); view_definition.reset(); if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset( allocator, raw_view_def, view_definition, CS_TYPE_UTF8MB4_GENERAL_CI, connection_collation))) { LOG_WARN("fail to copy and convert string charset", K(ret)); } return ret; } int ObSQLUtils::convert_sql_text_from_schema_for_resolve( ObIAllocator& allocator, const ObDataTypeCastParams& dtc_params, ObString& sql_text) { int ret = OB_SUCCESS; OZ(ObCharset::charset_convert(allocator, sql_text, CS_TYPE_UTF8MB4_BIN, dtc_params.connection_collation_, sql_text)); return ret; } int ObSQLUtils::convert_sql_text_to_schema_for_storing( ObIAllocator& allocator, const ObDataTypeCastParams& dtc_params, ObString& sql_text) { int ret = OB_SUCCESS; OZ(ObCharset::charset_convert(allocator, sql_text, dtc_params.connection_collation_, CS_TYPE_UTF8MB4_BIN, sql_text)); return ret; } int ObSQLUtils::print_identifier(char* buf, const int64_t buf_len, int64_t& pos, ObCollationType connection_collation, const common::ObString& identifier_name) { int ret = OB_SUCCESS; if (OB_ISNULL(buf)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else if (ObCharset::charset_type_by_coll(connection_collation) == CHARSET_UTF8MB4) { if (OB_UNLIKELY(pos + identifier_name.length() > buf_len)) { ret = OB_SIZE_OVERFLOW; LOG_WARN("size overflow", K(ret), K(identifier_name)); } else { MEMCPY(buf + pos, identifier_name.ptr(), identifier_name.length()); pos += identifier_name.length(); } } else if (OB_UNLIKELY(buf_len <= pos)) { ret = OB_SIZE_OVERFLOW; LOG_WARN("size overflow", K(ret)); } else { uint32_t result_len = 0; if (OB_FAIL(ObCharset::charset_convert(CS_TYPE_UTF8MB4_BIN, identifier_name.ptr(), identifier_name.length(), connection_collation, buf + pos, buf_len - pos, result_len))) { LOG_WARN("fail to convert charset", K(ret), K(buf_len), K(pos)); } else { pos += result_len; } } return ret; } int64_t ObSqlFatalErrExtraInfoGuard::to_string(char* buf, const int64_t buf_len) const { int ret = OB_SUCCESS; int64_t pos = 0; J_OBJ_START(); J_NEWLINE(); J_KV(K_(cur_sql)); const ObIArray* dep_tables = nullptr; ObString sys_var_values; if (OB_NOT_NULL(plan_)) { dep_tables = &(plan_->get_dependency_table()); sys_var_values = plan_->stat_.sys_vars_str_; } else if (OB_NOT_NULL(exec_ctx_)) { ObStmtFactory* stmt_factory = nullptr; ObQueryCtx* query_ctx = nullptr; if (OB_ISNULL(stmt_factory = exec_ctx_->get_stmt_factory()) || OB_ISNULL(query_ctx = stmt_factory->get_query_ctx())) { LOG_WARN("fail to get query ctx", K(ret)); } else { dep_tables = &(query_ctx->global_dependency_tables_); } if (OB_NOT_NULL(exec_ctx_->get_my_session())) { sys_var_values = exec_ctx_->get_my_session()->get_sys_var_in_pc_str(); } } if (OB_NOT_NULL(dep_tables)) { OZ(databuff_printf(buf, buf_len, pos, ", \ndependency_table_def:")); for (int i = 0; i < dep_tables->count(); ++i) { const ObSchemaObjVersion& schema_obj = dep_tables->at(i); if (schema_obj.get_schema_type() == TABLE_SCHEMA) { ObSchemaGetterGuard schema_guard; ObSchemaPrinter schema_printer(schema_guard); OZ(GCTX.schema_service_->get_tenant_schema_guard(tenant_id_, schema_guard, schema_obj.version_)); OZ(databuff_printf(buf, buf_len, pos, (i != 0) ? ",\n\"" : "\n\"")); OZ(schema_printer.print_table_definition( schema_obj.get_object_id(), buf, buf_len, pos, NULL, LS_DEFAULT, false)); OZ(databuff_printf(buf, buf_len, pos, "\"")); } } } if (!sys_var_values.empty()) { OZ(databuff_printf(buf, buf_len, pos, ",\nsys_vars:{")); for (int i = 0; i < ObSysVarFactory::ALL_SYS_VARS_COUNT; ++i) { if (!!(ObSysVariables::get_flags(i) & ObSysVarFlag::INFLUENCE_PLAN)) { ObString cur_var_value = sys_var_values.split_on(','); const char* sep_str = ","; if (cur_var_value.empty()) { cur_var_value = sys_var_values; sep_str = ""; } OZ(databuff_printf(buf, buf_len, pos, "\"%.*s\":\"%.*s\"%s", ObSysVariables::get_name(i).length(), ObSysVariables::get_name(i).ptr(), cur_var_value.length(), cur_var_value.ptr(), sep_str)); } } OZ(databuff_printf(buf, buf_len, pos, "}")); } // OX (plan_->print_tree(buf, buf_len, pos, plan_->get_main_query())); J_NEWLINE(); J_OBJ_END(); return pos; } bool ObSQLUtils::is_oracle_empty_string(const ObObjParam& param) { return (param.is_null() && ObCharType == param.get_param_meta().get_type()); } int ObSQLUtils::handle_audit_record( bool need_retry, const ObExecuteMode exec_mode, ObSQLSessionInfo& session, ObExecContext& exec_ctx) { int ret = OB_SUCCESS; if (need_retry) { /*do nothing*/ } else if (GCONF.enable_sql_audit) { if (session.get_local_ob_enable_sql_audit()) { FETCH_ENTITY(TENANT_SPACE, session.get_priv_tenant_id()) { ObMySQLRequestManager* req_manager = MTL_GET(ObMySQLRequestManager*); if (nullptr == req_manager) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get request manager for current tenant", K(ret)); } else { ObAuditRecordData audit_record = session.get_final_audit_record(exec_mode); audit_record.sched_info_ = exec_ctx.get_sched_info(); bool is_sensitive = (NULL != exec_ctx.get_sql_ctx()) ? exec_ctx.get_sql_ctx()->is_sensitive_ : true; if (OB_FAIL(req_manager->record_request(audit_record, is_sensitive))) { if (OB_SIZE_OVERFLOW == ret || OB_ALLOCATE_MEMORY_FAILED == ret) { LOG_DEBUG("cannot allocate mem for record", K(ret)); ret = OB_SUCCESS; } else { if (REACH_TIME_INTERVAL(100 * 1000)) { // in case logging is too frequent LOG_WARN("failed to record request info in request manager", K(ret)); } } } } } } } session.update_stat_from_audit_record(); session.reset_audit_record(); return ret; } bool ObSQLUtils::is_one_part_table_can_skip_part_calc(const ObTableSchema &schema) { bool can_skip = false; if (!schema.is_partitioned_table()) { can_skip = true; } else if (schema.get_all_part_num() == 1 && schema.is_hash_part()) { can_skip = true; } else { can_skip = false; } return can_skip; }