/** * 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_ENG #include "sql/engine/ob_phy_operator.h" #include "share/ob_worker.h" #include "lib/utility/ob_macro_utils.h" #include "common/sql_mode/ob_sql_mode_utils.h" #include "common/object/ob_obj_compare.h" #include "sql/ob_sql_utils.h" #include "sql/session/ob_sql_session_info.h" #include "sql/executor/ob_job_conf.h" #include "sql/executor/ob_receive.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/table/ob_table_scan.h" #include "sql/engine/expr/ob_sql_expression.h" #include "sql/engine/ob_physical_plan.h" #include "sql/monitor/ob_phy_plan_monitor_info.h" namespace oceanbase { using namespace common; namespace sql { OB_SERIALIZE_MEMBER(ColumnContent, projector_index_, auto_filled_timestamp_, column_name_, is_nullable_, is_implicit_, column_type_, coll_type_); OB_SERIALIZE_MEMBER(ObForeignKeyColumn, name_, idx_, name_idx_); OB_SERIALIZE_MEMBER(ObForeignKeyArg, ref_action_, table_name_, columns_, database_name_, is_self_ref_); OB_SERIALIZE_MEMBER(ObOpSchemaObj, obj_type_, is_not_null_, order_type_); ObPhyOperator::ObPhyOperator(ObIAllocator& alloc) : sql_expression_factory_(alloc), my_phy_plan_(NULL), parent_op_(NULL), id_(OB_INVALID_ID), column_count_(0), projector_size_(0), filter_exprs_(), calc_exprs_(), startup_exprs_(), virtual_column_exprs_(), rows_(0), cost_(0), width_(0), projector_(NULL), is_exact_rows_(false), type_(PHY_INVALID), plan_depth_(0), op_schema_objs_(alloc) {} ObPhyOperator::~ObPhyOperator() { reset(); } void ObPhyOperator::reset() { type_ = PHY_INVALID; my_phy_plan_ = NULL; parent_op_ = NULL; id_ = OB_INVALID_ID; column_count_ = 0; projector_ = NULL; projector_size_ = 0; // Embedded linked list, no memory management is involved, only clear() method, reset state back and forth filter_exprs_.reset(); calc_exprs_.reset(); startup_exprs_.reset(); virtual_column_exprs_.reset(); op_schema_objs_.reset(); } void ObPhyOperator::reuse() { type_ = PHY_INVALID; my_phy_plan_ = NULL; parent_op_ = NULL; id_ = OB_INVALID_ID; column_count_ = 0; projector_ = NULL; projector_size_ = 0; filter_exprs_.reset(); calc_exprs_.reset(); startup_exprs_.reset(); virtual_column_exprs_.reset(); op_schema_objs_.reset(); } int ObPhyOperator::handle_op_ctx(ObExecContext& ctx) const { int ret = OB_SUCCESS; ObPhyOperatorCtx* op_ctx = NULL; if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()))) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("get operator ctx failed", K(ret)); } else if (OB_FAIL(wrap_expr_ctx(ctx, op_ctx->expr_ctx_))) { LOG_WARN("wrap_expr_ctx failed", K(ret)); } return ret; } int ObPhyOperator::open(ObExecContext& ctx) const { int ret = OB_SUCCESS; OperatorOpenOrder open_order = get_operator_open_order(ctx); while (OB_SUCC(ret) && open_order != OPEN_EXIT) { switch (open_order) { case OPEN_CHILDREN_FIRST: case OPEN_CHILDREN_LATER: { ObPhyOperator* child_ptr = NULL; for (int32_t i = 0; OB_SUCC(ret) && i < get_child_num(); ++i) { if (OB_ISNULL(child_ptr = get_child(i))) { ret = OB_NOT_INIT; LOG_WARN("failed to get child", K(i), K(child_ptr), K(get_child_num()), K(ret)); } else if (OB_FAIL(child_ptr->open(ctx))) { if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) { LOG_WARN("Open child operator failed", K(ret), "op_type", ob_phy_operator_type_str(get_type())); } } else { } } open_order = (OPEN_CHILDREN_FIRST == open_order) ? OPEN_SELF_LATER : OPEN_EXIT; break; } case OPEN_SELF_FIRST: case OPEN_SELF_LATER: case OPEN_SELF_ONLY: { if (OB_FAIL(inner_open(ctx))) { if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) { LOG_WARN("Open this operator failed", K(ret), "op_type", ob_phy_operator_type_str(get_type())); } } else if (OB_FAIL(handle_op_ctx(ctx))) { LOG_WARN("handle op ctx failed ", K(ret)); } open_order = (OPEN_SELF_FIRST == open_order) ? OPEN_CHILDREN_LATER : OPEN_EXIT; break; } case OPEN_NONE: case OPEN_EXIT: { open_order = OPEN_EXIT; break; } default: ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected open order type", K(open_order)); break; } if (OB_FAIL(ret)) { if (OB_FAIL(process_expect_error(ctx, ret))) { if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) { LOG_WARN("fail to process error", K(ret)); } } } } if (OB_SUCC(ret)) { if (OB_FAIL(after_open(ctx))) { LOG_WARN("after open operator failed", K(ret), "op_type", ob_phy_operator_type_str(get_type()), K(id_)); } } LOG_DEBUG("open op", K(ret), "op_type", ob_phy_operator_type_str(get_type()), "op_id", get_id()); return ret; } int ObPhyOperator::process_expect_error(ObExecContext& ctx, int errcode) const { UNUSED(ctx); return errcode; } int ObPhyOperator::close(ObExecContext& ctx) const { int ret = OB_SUCCESS; int child_ret = OB_SUCCESS; OperatorOpenOrder open_order = get_operator_open_order(ctx); if (OPEN_SELF_ONLY != open_order && OPEN_NONE != open_order) { // first call close of all children ObPhyOperator* child_ptr = NULL; for (int32_t i = 0; i < get_child_num(); ++i) { // For the physical operator, when closing, regardless of whether the child's clos succeeds or fails, // all child closes must be called and not need to check ret if (OB_ISNULL(child_ptr = get_child(i))) { ret = OB_NOT_INIT; LOG_WARN("failed to get child", K(i), K(child_ptr), K(get_child_num()), K(ret), "op_type", ob_phy_operator_type_str(get_type())); } else { int tmp_ret = child_ptr->close(ctx); if (OB_SUCCESS != tmp_ret) { child_ret = tmp_ret; LOG_WARN("Close child operator failed", K(child_ret), "op_type", ob_phy_operator_type_str(get_type())); } } } } ObPhyOperatorCtx* op_ctx = NULL; if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()))) { LOG_DEBUG("get_phy_operator_ctx failed", K(ret), K_(id), "op_type", ob_phy_operator_type_str(get_type())); } if (OPEN_NONE != open_order) { // no matter what, must call operatoris close function, then close this operator if (OB_FAIL(inner_close(ctx))) { LOG_WARN("Close this operator failed", K(ret), "op_type", ob_phy_operator_type_str(get_type())); } else if (op_ctx) { op_ctx->op_monitor_info_.close_time_ = oceanbase::common::ObClockGenerator::getClock(); } } if (OB_SUCC(ret)) { // Can only preserve one error code ret = child_ret; } if (GCONF.enable_sql_audit) { // Record current operator statistics to sql_plan_monitor, inner_sql will not be counted ObPlanMonitorNodeList* list = MTL_GET(ObPlanMonitorNodeList*); if (op_ctx && list && my_phy_plan_ && ctx.get_my_session()->is_user_session() && OB_PHY_PLAN_LOCAL != my_phy_plan_->get_plan_type() && OB_PHY_PLAN_REMOTE != my_phy_plan_->get_plan_type()) { op_ctx->op_monitor_info_.set_plan_depth(plan_depth_); IGNORE_RETURN list->submit_node(op_ctx->op_monitor_info_); } } return ret; } int ObPhyOperator::rescan(ObExecContext& ctx) const { // rescan must reset the oeprator context to the state after call operator open() // for the general non-terminal operator, function rescan() is to call children rescan() // if you want to do more, you must rewrite this function // for the general terminal operator, function rescan() does nothing // you can rewrite it to complete special function int ret = OB_SUCCESS; ObPhyOperator* child_op = NULL; for (int32_t i = 0; OB_SUCC(ret) && i < get_child_num(); ++i) { if (OB_ISNULL(child_op = get_child(i))) { LOG_WARN("failed to get child", K(i), K(child_op), K(get_child_num()), K(ret)); } else if (OB_FAIL(child_op->rescan(ctx))) { LOG_WARN("rescan child operator failed", K(ret), K(i), "op_type", ob_phy_operator_type_str(get_type()), "child op_type", ob_phy_operator_type_str(child_op->get_type())); } else { } } ObPhyOperatorCtx* op_ctx = NULL; if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_phy_operator_ctx failed", K(ret), K_(id), "op_type", ob_phy_operator_type_str(get_type())); } else { op_ctx->is_filtered_has_set_ = false; op_ctx->op_monitor_info_.rescan_times_++; } return ret; } int ObPhyOperator::switch_iterator(ObExecContext& ctx) const { int ret = OB_SUCCESS; ObPhyOperator* child_op = NULL; ObPhyOperatorCtx* op_ctx = NULL; ObPhysicalPlanCtx* plan_ctx = NULL; if (OB_ISNULL(plan_ctx = GET_PHY_PLAN_CTX(ctx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan ctx is null", K(ret)); } else if (plan_ctx->get_bind_array_count() <= 0) { ret = OB_ITER_END; } else if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_phy_operator_ctx failed", K(ret), K_(id), "op_type", ob_phy_operator_type_str(get_type())); } else { op_ctx->is_filtered_has_set_ = false; // op_ctx->op_monitor_info_.increase_value(RESCAN_TIMES); ++op_ctx->expr_ctx_.cur_array_index_; } for (int32_t i = 0; OB_SUCC(ret) && i < get_child_num(); ++i) { if (OB_ISNULL(child_op = get_child(i))) { LOG_WARN("failed to get child", K(i), K(child_op), K(get_child_num()), K(ret)); } else if (OB_FAIL(child_op->switch_iterator(ctx))) { if (OB_ITER_END != ret) { LOG_WARN("switch child operator iterator failed", K(ret), "op_type", ob_phy_operator_type_str(get_type()), "child op_type", ob_phy_operator_type_str(child_op->get_type())); } } else { } } return ret; } OB_DEF_SERIALIZE(ObPhyOperator) { int ret = OB_SUCCESS; if (OB_FAIL(serialize_dlist(calc_exprs_, buf, buf_len, pos))) { LOG_WARN("failed to serialize calc_exprs_", K(ret)); } else if (OB_FAIL(serialize_dlist(filter_exprs_, buf, buf_len, pos))) { LOG_WARN("failed to serialize filter_exprs_", K(ret)); } else if (OB_FAIL(serialize_dlist(startup_exprs_, buf, buf_len, pos))) { LOG_WARN("failed to serialize startup_exprs_", K(ret)); } OB_UNIS_ENCODE(static_cast(id_)); OB_UNIS_ENCODE(column_count_); OB_UNIS_ENCODE_ARRAY(projector_, projector_size_); if (OB_SUCC(ret)) { if (OB_FAIL(serialize_dlist(virtual_column_exprs_, buf, buf_len, pos))) { LOG_WARN("failed to serialize startup_exprs_", K(ret)); } } OB_UNIS_ENCODE(op_schema_objs_); OB_UNIS_ENCODE(is_exact_rows_); OB_UNIS_ENCODE(rows_); OB_UNIS_ENCODE(width_); OB_UNIS_ENCODE(px_est_size_factor_); OB_UNIS_ENCODE(plan_depth_); return ret; } OB_DEF_DESERIALIZE(ObPhyOperator) { int ret = OB_SUCCESS; int64_t id_int64 = 0; if (OB_ISNULL(my_phy_plan_)) { ret = OB_NOT_INIT; LOG_WARN("physical plan is null"); } OB_UNIS_DECODE_EXPR_DLIST(ObColumnExpression, calc_exprs_, my_phy_plan_); OB_UNIS_DECODE_EXPR_DLIST(ObSqlExpression, filter_exprs_, my_phy_plan_); OB_UNIS_DECODE_EXPR_DLIST(ObSqlExpression, startup_exprs_, my_phy_plan_); OB_UNIS_DECODE(id_int64); OB_UNIS_DECODE(column_count_); if (OB_SUCC(ret)) { id_ = static_cast(id_int64); } if (OB_SUCC(ret)) { OB_UNIS_DECODE(projector_size_); if (projector_size_ > 0) { ObIAllocator& alloc = my_phy_plan_->get_allocator(); if (OB_ISNULL(projector_ = static_cast(alloc.alloc(sizeof(int32_t) * projector_size_)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("no memory", K_(projector_size)); } else { OB_UNIS_DECODE_ARRAY(projector_, projector_size_); } } else { projector_ = NULL; } } if (OB_SUCC(ret)) { OB_UNIS_DECODE_EXPR_DLIST(ObColumnExpression, virtual_column_exprs_, my_phy_plan_); OB_UNIS_DECODE(op_schema_objs_); OB_UNIS_DECODE(is_exact_rows_); OB_UNIS_DECODE(rows_); OB_UNIS_DECODE(width_); OB_UNIS_DECODE(px_est_size_factor_); OB_UNIS_DECODE(plan_depth_); } return ret; } OB_DEF_SERIALIZE_SIZE(ObPhyOperator) { int64_t len = 0; len += get_dlist_serialize_size(calc_exprs_); len += get_dlist_serialize_size(filter_exprs_); len += get_dlist_serialize_size(startup_exprs_); OB_UNIS_ADD_LEN(static_cast(id_)); OB_UNIS_ADD_LEN(column_count_); OB_UNIS_ADD_LEN_ARRAY(projector_, projector_size_); len += get_dlist_serialize_size(virtual_column_exprs_); OB_UNIS_ADD_LEN(op_schema_objs_); OB_UNIS_ADD_LEN(is_exact_rows_); OB_UNIS_ADD_LEN(rows_); OB_UNIS_ADD_LEN(width_); OB_UNIS_ADD_LEN(px_est_size_factor_); OB_UNIS_ADD_LEN(plan_depth_); return len; } int ObPhyOperator::add_filter(ObSqlExpression* expr, bool startup) { int ret = OB_SUCCESS; if (startup) { if (OB_FAIL(ObSqlExpressionUtil::add_expr_to_list(startup_exprs_, expr))) { OB_LOG(WARN, "fail to add expr to list", K(ret)); } } else { if (OB_FAIL(ObSqlExpressionUtil::add_expr_to_list(filter_exprs_, expr))) { OB_LOG(WARN, "fail to ad expr to list", K(ret)); } } return ret; } int ObPhyOperator::add_virtual_column_expr(ObColumnExpression* expr) { return ObSqlExpressionUtil::add_expr_to_list(virtual_column_exprs_, expr); } int ObPhyOperator::add_compute(ObColumnExpression* expr) { return ObSqlExpressionUtil::add_expr_to_list(calc_exprs_, expr); } int ObPhyOperator::get_next_row(ObExecContext& ctx, const ObNewRow*& row) const { int ret = OB_SUCCESS; const ObNewRow* input_row = NULL; bool is_filtered = false; ObPhyOperatorCtx* op_ctx = NULL; if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_phy_operator_ctx failed", K(ret), K_(id), "op_type", ob_phy_operator_type_str(get_type())); } else if (OB_ISNULL(op_ctx->expr_ctx_.calc_buf_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("calc buffer is null", K(ret), K(get_id())); } else if (!op_ctx->is_filtered_has_set_) { if (OB_FAIL(startup_filter(op_ctx->expr_ctx_, op_ctx->is_filtered_))) { LOG_WARN("call startup_filter failed", K(ret), K(op_ctx->is_filtered_)); } else { op_ctx->is_filtered_has_set_ = true; } } if (OB_SUCC(ret)) { if (op_ctx->is_filtered_) { ret = OB_ITER_END; } } while (OB_SUCC(ret)) { op_ctx->expr_ctx_.calc_buf_->reuse(); op_ctx->expr_ctx_.row_ctx_.reset(); if (OB_FAIL(inner_get_next_row(ctx, input_row))) { if (OB_ITER_END != ret) { LOG_WARN("get next row failed", K(ret), K_(type), K_(id), "op", ob_phy_operator_type_str(get_type())); } } else { if (need_filter_row() && OB_FAIL(filter_row(op_ctx->expr_ctx_, *input_row, is_filtered))) { // filter the row LOG_WARN("call filter_row failed", K(ret), K_(type), K_(id), "op", ob_phy_operator_type_str(get_type())); } else if (!is_filtered) { // not be filtered, break break; } else { } } // be filtered, continue to get next row } // calculate if (OB_SUCC(ret)) { ObNewRow* calc_row = const_cast(input_row); if (OB_FAIL(calculate_row(op_ctx->expr_ctx_, *calc_row))) { LOG_WARN("calculate row failed", K(ret)); } else { row = calc_row; if (!op_ctx->got_first_row_) { op_ctx->op_monitor_info_.first_row_time_ = oceanbase::common::ObClockGenerator::getClock(); op_ctx->got_first_row_ = true; } op_ctx->op_monitor_info_.output_row_count_++; } } if (OB_ITER_END == ret && NULL != op_ctx) { int tmp_ret = drain_exch(ctx); if (OB_SUCCESS != tmp_ret) { LOG_WARN("drain exchange data failed", K(tmp_ret)); } if (op_ctx->got_first_row_) { op_ctx->op_monitor_info_.last_row_time_ = oceanbase::common::ObClockGenerator::getClock(); } } return ret; } int ObPhyOperator::get_next_rows(ObExecContext& ctx, const ObNewRow*& rows, int64_t& row_count) const { int ret = get_next_row(ctx, rows); if (OB_SUCCESS == ret) { row_count = 1; } else { row_count = 0; } return ret; } int ObPhyOperator::inner_open(ObExecContext& ctx) const { UNUSED(ctx); return OB_SUCCESS; } int ObPhyOperator::after_open(ObExecContext& ctx) const { UNUSED(ctx); return OB_SUCCESS; } int ObPhyOperator::inner_close(ObExecContext& ctx) const { UNUSED(ctx); return OB_SUCCESS; } int ObPhyOperator::startup_filter(ObExprCtx& expr_ctx, bool& is_filtered) const { int ret = OB_SUCCESS; bool is_true = false; is_filtered = false; ObObj result; ObNewRow empty_row; if (!startup_exprs_.is_empty()) { DLIST_FOREACH(p, startup_exprs_) { result.reset(); if (OB_ISNULL(p)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null"); } else if (OB_FAIL(p->calc(expr_ctx, empty_row, result))) { LOG_WARN("failed to calc expression", K(ret), K(*p)); } else if (OB_FAIL(ObObjEvaluator::is_true(result, is_true))) { LOG_WARN("failed to call is true", K(ret)); } else if (!is_true) { // the row is filtered, break to get next row is_filtered = true; break; } else { } } // end for } return ret; } inline int ObPhyOperator::filter_row(ObExprCtx& expr_ctx, const ObNewRow& row, bool& is_filtered) const { int ret = OB_SUCCESS; is_filtered = false; if (OB_FAIL(filter_row(expr_ctx, row, filter_exprs_, is_filtered))) { LOG_WARN("failed to filter row", K(ret)); } else { // now some cells in row maybe wild pointer, these cells will be set in calculate_row later, // so we can't print row here. LOG_DEBUG("got 1 row from child", "op_type", ob_phy_operator_type_str(get_type()), /*K(row),*/ K(is_filtered)); } return ret; } int ObPhyOperator::filter_row( ObExprCtx& expr_ctx, const ObNewRow& row, const ObDList& filters, bool& is_filtered) const { int ret = OB_SUCCESS; is_filtered = false; if (OB_UNLIKELY(NULL == row.cells_ || row.count_ <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("row is not init", K(ret)); } else if (!filters.is_empty()) { DLIST_FOREACH(p, filters) { if (OB_FAIL(filter_row_inner(expr_ctx, row, p, is_filtered))) { LOG_WARN("fail to filter row", K(ret)); } else if (is_filtered) { break; } } // end for } return ret; } int ObPhyOperator::filter_row_for_check_cst( ObExprCtx& expr_ctx, const ObNewRow& row, const ObDList& filters, bool& is_filtered) const { int ret = OB_SUCCESS; is_filtered = false; if (OB_UNLIKELY(NULL == row.cells_ || row.count_ <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("row is not init", K(ret)); } else if (!filters.is_empty()) { DLIST_FOREACH(p, filters) { if (OB_FAIL(filter_row_inner_for_check_cst(expr_ctx, row, p, is_filtered))) { LOG_WARN("fail to filter row", K(ret)); } else if (is_filtered) { break; } } // end for } return ret; } int ObPhyOperator::filter_row( ObExprCtx& expr_ctx, const ObNewRow& row, const ObIArray& filters, bool& is_filtered) { int ret = OB_SUCCESS; is_filtered = false; for (int64_t i = 0; OB_SUCC(ret) && i < filters.count(); ++i) { if (OB_FAIL(filter_row_inner(expr_ctx, row, filters.at(i), is_filtered))) { LOG_WARN("fail to filter row", K(ret)); } else if (is_filtered) { break; } } return ret; } int ObPhyOperator::filter_row_inner_for_check_cst( ObExprCtx& expr_ctx, const ObNewRow& row, const ObISqlExpression* expr, bool& is_filtered) { int ret = OB_SUCCESS; ObObj result; bool is_false = false; if (OB_ISNULL(expr) || OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(expr), K(expr_ctx.calc_buf_), K(ret)); } else if (OB_FAIL(expr->calc(expr_ctx, row, result))) { LOG_WARN("failed to calc expression", K(ret), K(*expr)); } else if (OB_FAIL(ObObjEvaluator::is_false(result, is_false))) { LOG_WARN("failed to call is true", K(ret)); } else { if (is_false) { expr_ctx.calc_buf_->reuse(); // the row is filtered, break to get next row is_filtered = true; } } return ret; } int ObPhyOperator::filter_row_inner( ObExprCtx& expr_ctx, const ObNewRow& row, const ObISqlExpression* expr, bool& is_filtered) { int ret = OB_SUCCESS; ObObj result; bool is_true = false; if (OB_ISNULL(expr) || OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(expr), K(expr_ctx.calc_buf_), K(ret)); } else if (OB_FAIL(expr->calc(expr_ctx, row, result))) { LOG_WARN("failed to calc expression", K(ret), K(*expr)); } else if (OB_FAIL(ObObjEvaluator::is_true(result, is_true))) { LOG_WARN("failed to call is true", K(ret)); } else { // PLEASE...DO NOT DELETE ME...JUST LEAVE ME ALONE 'CAUSE ONE DAY I WOULD if (!is_true) { expr_ctx.calc_buf_->reuse(); // the row is filtered, break to get next row is_filtered = true; } } return ret; } int ObPhyOperator::calculate_row(common::ObExprCtx& expr_ctx, common::ObNewRow& calc_row) const { return calculate_row_inner(expr_ctx, calc_row, calc_exprs_); } int ObPhyOperator::calculate_virtual_column(common::ObExprCtx& expr_ctx, common::ObNewRow& calc_row) const { return calculate_row_inner(expr_ctx, calc_row, virtual_column_exprs_); } int ObPhyOperator::calculate_row_inner( ObExprCtx& expr_ctx, ObNewRow& calc_row, const ObDList& calc_exprs) const { int ret = OB_SUCCESS; const ObColumnExpression* p = NULL; if (OB_UNLIKELY(NULL == calc_row.cells_ || calc_row.count_ <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("row is not init"); } else if (!calc_exprs.is_empty()) { DLIST_FOREACH(node, calc_exprs) { p = static_cast(node); if (OB_UNLIKELY(NULL == node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null"); } else if (OB_FAIL(p->calc_and_project(expr_ctx, calc_row))) { LOG_WARN("calculate column expression failed", K(ret), K(*p), "op_type", ob_phy_operator_type_str(get_type())); expr_ctx.err_col_idx_ = calc_row.get_project_idx(p->get_result_index()); } else { } } LOG_DEBUG("calculate row", K(ret), "op_type", ob_phy_operator_type_str(get_type()), K(calc_row)); } return ret; } int ObPhyOperator::init_cur_row(ObPhyOperatorCtx& op_ctx, bool need_create_cells) const { int ret = OB_SUCCESS; if (need_create_cells && get_column_count() > 0) { // Need to create a cells array for the current row, this time the child row will be actually copied to the current // row if (OB_FAIL(op_ctx.create_cur_row(get_column_count(), projector_, projector_size_))) { LOG_WARN("create current row failed", K(ret)); } } else { ObNewRow& cur_row = op_ctx.get_cur_row(); cur_row.cells_ = NULL; cur_row.count_ = get_column_count(); cur_row.projector_ = projector_; cur_row.projector_size_ = projector_size_; } return ret; } int ObPhyOperator::init_cur_rows(int64_t row_count, ObPhyOperatorCtx& op_ctx, bool need_create_cells) const { int ret = OB_SUCCESS; if (need_create_cells && get_column_count() > 0) { // Need to create a cells array for the current row, this time the child row will be actually copied to the current // row if (OB_FAIL(op_ctx.create_cur_rows(row_count, get_column_count(), projector_, projector_size_))) { LOG_WARN("create current rows failed", K(ret)); } } else { ObNewRow* cur_rows = op_ctx.get_cur_rows(); int64_t row_count = op_ctx.get_row_count(); for (int i = 0; i < row_count; i++) { cur_rows[i].cells_ = NULL; cur_rows[i].count_ = get_column_count(); cur_rows[i].projector_ = projector_; cur_rows[i].projector_size_ = projector_size_; } } return ret; } int ObPhyOperator::ObPhyOperatorCtx::alloc_row_cells(const int64_t column_count, common::ObNewRow& row) { int ret = OB_SUCCESS; void* ptr = NULL; if (column_count <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(column_count)); } else if (OB_ISNULL(ptr = exec_ctx_.get_allocator().alloc(column_count * sizeof(ObObj)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("alloc memory for row failed", "size", column_count * sizeof(ObObj)); } else { // This is not initializing, but assigning a value to the row object. What is passed // here is a reference, not a pointer. The initialization of all members should be managed by the caller row.cells_ = new (ptr) common::ObObj[column_count]; row.count_ = column_count; } return ret; } int ObPhyOperator::ObPhyOperatorCtx::alloc_rows_cells( const int64_t row_count, const int64_t column_count, common::ObNewRow* rows) { int ret = OB_SUCCESS; void* ptr = NULL; if (row_count <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(column_count)); } else if (column_count <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(column_count)); } else if (OB_ISNULL(ptr = exec_ctx_.get_allocator().alloc(row_count * column_count * sizeof(ObObj)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("alloc memory for row failed", "size", row_count * column_count * sizeof(ObObj)); } else { // This is not initializing, but assigning a value to the row object. What is passed // here is a reference, not a pointer. The initialization of all members should be managed by the caller for (int64_t i = 0; i < row_count; i++) { long unsigned offset = i * column_count * sizeof(ObObj); rows[i].cells_ = new (static_cast(ptr) + offset) common::ObObj[column_count]; rows[i].count_ = column_count; } } return ret; } int ObPhyOperator::ObPhyOperatorCtx::create_cur_rows( int64_t row_count, int64_t column_count, int32_t* projector, int64_t projector_size) { int ret = OB_SUCCESS; if (row_count <= 0 || column_count <= 0 || (projector == NULL && projector_size > 0) || (projector != NULL && projector_size == 0)) { ret = OB_INVALID_ARGUMENT; SQL_ENG_LOG(WARN, "invalid argument", K(row_count), K(column_count), K(projector), K(projector_size)); } else if (row_count > BULK_COUNT) { row_count = BULK_COUNT; } row_count_ = row_count; void* ptr = NULL; if (OB_FAIL(ret)) { } else if (OB_ISNULL(ptr = exec_ctx_.get_allocator().alloc(row_count_ * sizeof(ObNewRow)))) { ret = OB_ALLOCATE_MEMORY_FAILED; SQL_ENG_LOG(ERROR, "alloc memory for row failed", "size", row_count_ * sizeof(ObNewRow)); } else { cur_rows_ = new (ptr) ObNewRow[row_count_]; if (OB_SUCCESS == (ret = alloc_rows_cells(row_count_, column_count, cur_rows_))) { for (int64_t i = 0; i < row_count_; i++) { cur_rows_[i].projector_ = projector; cur_rows_[i].projector_size_ = projector_size; } column_count_ = column_count; projector_ = projector; projector_size_ = projector_size; } } return ret; } // Copy the row cells to the current row in the physical operator context and keep the physical location of the original // row cells int ObPhyOperator::copy_cur_row(ObPhyOperatorCtx& op_ctx, const ObNewRow*& row) const { int ret = OB_SUCCESS; if (OB_FAIL(copy_cur_row(op_ctx.get_cur_row(), row, need_copy_row_for_compute()))) { LOG_WARN("copy current row failed", K(ret)); } return ret; } int ObPhyOperator::copy_cur_row(ObNewRow& cur_row, const ObNewRow*& row, bool need_copy_cell) const { int ret = OB_SUCCESS; cur_row.count_ = column_count_; cur_row.projector_ = projector_; cur_row.projector_size_ = projector_size_; if (OB_ISNULL(row)) { ret = OB_INVALID_ARGUMENT; } else if (OB_UNLIKELY(need_copy_cell)) { int64_t real_count = row->get_count(); for (int64_t i = 0; OB_SUCC(ret) && i < real_count; ++i) { int64_t real_idx = row->projector_size_ > 0 ? row->projector_[i] : i; // In order to minimize copying, only copy the columns projected by the child operator // Because the materialization operations for compute are special, The row_desc of // this layer and the row_desc of the child operator are exactly the same and so // it needs to be copied to its own corresponding position, and the physical position // of the child operator must be one-to-one correspondence. The cells filtered by // projection do not need to be copied, and these cells will not be used in this layer if (OB_UNLIKELY(real_idx >= row->count_ || real_idx >= cur_row.count_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid row count", K(real_idx), K_(row->count), K_(cur_row.count)); } else { cur_row.cells_[real_idx] = row->cells_[real_idx]; } } } else if (OB_UNLIKELY(cur_row.count_ != row->count_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("current row is not equal", K_(cur_row.count), K_(row->count)); } else { // No need to copy the cell, only need to reproject the current row of the child operator to the current row cur_row.cells_ = row->cells_; } if (OB_SUCC(ret)) { row = &cur_row; } return ret; } int ObPhyOperator::copy_cur_row_by_projector(ObNewRow& cur_row, const ObNewRow*& row) const { int ret = OB_SUCCESS; int64_t col_cnt = 0; if (OB_ISNULL(row) || OB_UNLIKELY(cur_row.is_invalid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("row is null", K(row), "cur_row", cur_row); } else if (OB_UNLIKELY(&cur_row == row)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("self assignment. current row has same address with row", K(ret)); } else { col_cnt = min(cur_row.count_, row->get_count()); } for (int64_t i = 0; OB_SUCC(ret) && i < col_cnt; ++i) { cur_row.cells_[i] = row->get_cell(i); } // set rest objs to be nulltype in case of prone bugs for (int64_t i = row->get_count(); OB_SUCC(ret) && i < cur_row.count_; ++i) { cur_row.cells_[i].set_null(); } row = &cur_row; return ret; } int ObPhyOperator::copy_cur_row_by_projector(ObPhyOperatorCtx& op_ctx, const ObNewRow*& row) const { int ret = OB_SUCCESS; ObNewRow& cur_row = op_ctx.get_cur_row(); if (OB_FAIL(copy_cur_row_by_projector(cur_row, row))) { LOG_WARN("fail to copy row by projector", K(row), K(cur_row), K(ret)); } return ret; } int ObPhyOperator::copy_cur_rows_by_projector(ObPhyOperatorCtx& op_ctx, const ObNewRow*& row) const { int ret = OB_SUCCESS; ObNewRow* cur_row = NULL; if (op_ctx.index_ >= op_ctx.row_count_) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("index is not valid", K(op_ctx.index_), K(ret)); } else { cur_row = &op_ctx.get_cur_rows()[op_ctx.index_]; if (OB_FAIL(copy_cur_row_by_projector(*cur_row, row))) { LOG_WARN("fail to copy row by projector", K(op_ctx.row_count_), K(op_ctx.index_), K(row), K(*cur_row), K(ret)); } else { op_ctx.index_++; } } return ret; } int ObPhyOperator::copy_cur_rows(ObPhyOperatorCtx& op_ctx, const ObNewRow*& row, bool need_copy_cell) const { int ret = OB_SUCCESS; ObNewRow* cur_row = NULL; if (op_ctx.index_ >= op_ctx.row_count_) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("index is not valid", K(op_ctx.index_), K(ret)); } else { cur_row = &op_ctx.get_cur_rows()[op_ctx.index_]; if (OB_FAIL(copy_cur_row(*cur_row, row, need_copy_cell))) { LOG_WARN("fail to copy row failed", K(row), K(*cur_row), K(ret)); } else { op_ctx.index_++; } } return ret; } int ObPhyOperator::wrap_expr_ctx(ObExecContext& exec_ctx, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; ObPhysicalPlanCtx* phy_plan_ctx = NULL; ObSQLSessionInfo* my_session = NULL; ObPhyOperatorCtx* phy_op_ctx = NULL; const ObTimeZoneInfo* tz_info = NULL; int64_t tz_offset = 0; if (OB_ISNULL(phy_plan_ctx = exec_ctx.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_physical_plan_ctx failed", K(ret)); } else if (OB_ISNULL(my_session = exec_ctx.get_my_session())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get session failed", K(ret)); } else if (OB_ISNULL(phy_op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, exec_ctx, get_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get_phy_operator_ctx failed", K(ret), K_(id), "op_type", ob_phy_operator_type_str(get_type())); } 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 { ObMemAttr mem_attr(my_session->get_effective_tenant_id(), ObModIds::OB_SQL_EXPR_CALC); phy_op_ctx->get_calc_buf().set_attr(mem_attr); expr_ctx.phy_plan_ctx_ = phy_plan_ctx; expr_ctx.my_session_ = my_session; expr_ctx.exec_ctx_ = &exec_ctx; expr_ctx.calc_buf_ = &(phy_op_ctx->get_calc_buf()); expr_ctx.tz_offset_ = tz_offset; expr_ctx.phy_operator_ctx_id_ = get_id(); if (OB_FAIL(ObSQLUtils::get_default_cast_mode(my_phy_plan_->get_stmt_type(), my_session, expr_ctx.cast_mode_))) { LOG_WARN("get default cast mode failed", K(ret)); } else if (OB_FAIL(ObSQLUtils::wrap_column_convert_ctx(expr_ctx, expr_ctx.column_conv_ctx_))) { LOG_WARN("wrap column convert ctx failed", K(ret)); } } return ret; } int ObPhyOperator::create_operator_input(ObExecContext& ctx) const { UNUSED(ctx); return OB_SUCCESS; } DEF_TO_STRING(ObPhyOperator) { int64_t pos = 0; int64_t parent_pos = 0; int64_t child_len = 0; J_OBJ_START(); J_KV(N_ID, id_, N_TYPE, type_, N_COLUMN_COUNT, column_count_, N_PROJECTOR, ObArrayWrap(projector_, projector_size_), N_FILTER_EXPRS, filter_exprs_, N_CALC_EXPRS, calc_exprs_); parent_pos = pos; J_COMMA(); child_len = to_string_kv(buf + pos, buf_len - pos); if (child_len <= 0) { pos = parent_pos; } else { pos += child_len; } J_OBJ_END(); return pos; } int ObPhyOperator::check_status(ObExecContext& ctx) const { int ret = OB_SUCCESS; if (OB_FAIL(ctx.check_status())) { LOG_WARN("ctx status check failed", "op_type", ob_phy_operator_type_str(get_type())); } return ret; } int ObPhyOperator::try_check_status(ObExecContext& ctx) const { int ret = OB_SUCCESS; ObPhyOperatorCtx* op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()); if (OB_ISNULL(op_ctx)) { ret = OB_NOT_INIT; LOG_WARN("op ctx is null", K(ret)); } else { ++op_ctx->check_times_; if (0 == (CHECK_STATUS_MASK & op_ctx->check_times_)) { ret = check_status(ctx); } } return ret; } int ObPhyOperator::drain_exch(ObExecContext& ctx) const { int ret = OB_SUCCESS; ObPhyOperatorCtx* op_ctx = nullptr; /** * 1. try to open this operator * 2. try to drain all children */ if (OB_FAIL(try_open_and_get_operator_ctx(ctx, op_ctx))) { LOG_WARN("fail to get operator ctx", K(ret)); } else if (!op_ctx->exch_drained_) { op_ctx->exch_drained_ = true; const int32_t child_num = get_child_num(); for (int32_t i = 0; i < child_num && OB_SUCC(ret); i++) { const ObPhyOperator* child = get_child(i); if (OB_ISNULL(child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL child found", K(ret)); } else if (OB_FAIL(child->drain_exch(ctx))) { LOG_WARN("drain exch failed", K(ret)); } } } return ret; } int ObPhyOperator::register_to_datahub(ObExecContext& ctx) const { UNUSED(ctx); return OB_SUCCESS; } int ObPhyOperator::open_child(ObExecContext& ctx, const int32_t child_idx) const { int ret = OB_SUCCESS; ObPhyOperator* child_ptr = nullptr; if (OB_ISNULL(child_ptr = get_child(child_idx))) { ret = OB_NOT_INIT; LOG_WARN("failed to get child", K(ret), K(child_ptr), K(get_child_num()), K(child_idx)); } else if (OB_FAIL(child_ptr->open(ctx))) { if (OB_TRY_LOCK_ROW_CONFLICT != ret && OB_TRANSACTION_SET_VIOLATION != ret) { LOG_WARN("Open child operator failed", K(ret), "op_type", ob_phy_operator_type_str(get_type())); } } return ret; } int ObPhyOperator::get_real_child(ObPhyOperator*& child, const int32_t child_idx) const { int ret = OB_SUCCESS; const int32_t first_child_idx = 0; ObPhyOperator* first_child = nullptr; if (first_child_idx >= get_child_num()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid child idx", K(ret), K(get_child_num())); } else if (OB_ISNULL(first_child = get_child(first_child_idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected null child", K(ret)); } else if (IS_DUMMY_PHY_OPERATOR(first_child->get_type())) { if (OB_FAIL(first_child->get_real_child(child, child_idx))) { LOG_WARN("Failed to get real child", K(ret), K(first_child->get_type())); } } else { child = get_child(child_idx); if (OB_ISNULL(child)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Get a null child", K(ret)); } } return ret; } int ObPhyOperator::deep_copy_row(const ObNewRow& src_row, ObNewRow*& dst_row, ObIAllocator& allocator) { int ret = OB_SUCCESS; char* buf = nullptr; int64_t pos = sizeof(ObNewRow); ObNewRow* new_row = nullptr; int64_t buf_len = src_row.get_deep_copy_size() + sizeof(ObNewRow); if (OB_ISNULL(buf = static_cast(allocator.alloc(buf_len)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc new row", K(ret), K(buf_len)); } else if (OB_ISNULL(new_row = new (buf) ObNewRow())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected null new row", K(ret), K(buf_len)); } else if (OB_FAIL(new_row->deep_copy(src_row, buf, buf_len, pos))) { LOG_WARN("Failed to deep copy row", K(ret), K(buf_len), K(pos)); } else { dst_row = new_row; } return ret; } int ObPhyOperator::try_open_and_get_operator_ctx( ObExecContext& ctx, ObPhyOperatorCtx*& op_ctx, bool* has_been_opened) const { int ret = OB_SUCCESS; if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()))) { // we should open this operator first if (OB_NOT_NULL(has_been_opened)) { *has_been_opened = false; } else if (OB_FAIL(open(ctx))) { LOG_WARN("fail to open this operator", K(ret), K(type_)); } else if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObPhyOperatorCtx, ctx, get_id()))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("get operator ctx failed", K(ret), K(get_id()), K(get_name())); } } else if (OB_NOT_NULL(has_been_opened)) { *has_been_opened = true; } return ret; } int ObPhyOperator::init_op_schema_obj(int64_t count) { int ret = OB_SUCCESS; if (OB_FAIL(op_schema_objs_.init(count))) { LOG_WARN("fail to init op schema obj", K(ret), K(count)); } return ret; } } // namespace sql } // namespace oceanbase