oceanbase/src/sql/code_generator/ob_static_engine_cg.cpp

6707 lines
284 KiB
C++

/**
* 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 "ob_static_engine_cg.h"
#include "sql/optimizer/ob_logical_operator.h"
#include "sql/optimizer/ob_log_group_by.h"
#include "sql/optimizer/ob_log_table_scan.h"
#include "sql/optimizer/ob_log_sort.h"
#include "sql/optimizer/ob_log_limit.h"
#include "sql/optimizer/ob_log_sequence.h"
#include "sql/optimizer/ob_log_join.h"
#include "sql/optimizer/ob_log_join_filter.h"
#include "sql/optimizer/ob_log_exchange.h"
#include "sql/optimizer/ob_log_for_update.h"
#include "sql/optimizer/ob_log_delete.h"
#include "sql/optimizer/ob_log_insert.h"
#include "sql/optimizer/ob_log_update.h"
#include "sql/optimizer/ob_log_merge.h"
#include "sql/optimizer/ob_log_expr_values.h"
#include "sql/optimizer/ob_log_function_table.h"
#include "sql/optimizer/ob_log_values.h"
#include "sql/optimizer/ob_log_set.h"
#include "sql/optimizer/ob_log_subplan_filter.h"
#include "sql/optimizer/ob_log_subplan_scan.h"
#include "sql/optimizer/ob_log_material.h"
#include "sql/optimizer/ob_log_distinct.h"
#include "sql/optimizer/ob_log_window_function.h"
#include "sql/optimizer/ob_log_select_into.h"
#include "sql/optimizer/ob_log_topk.h"
#include "sql/optimizer/ob_log_count.h"
#include "sql/optimizer/ob_log_granule_iterator.h"
#include "sql/optimizer/ob_log_table_lookup.h"
#include "sql/optimizer/ob_log_link.h"
#include "sql/optimizer/ob_log_monitoring_dump.h"
#include "sql/optimizer/ob_log_temp_table_access.h"
#include "sql/optimizer/ob_log_temp_table_insert.h"
#include "sql/optimizer/ob_log_temp_table_transformation.h"
#include "sql/optimizer/ob_log_unpivot.h"
#include "sql/optimizer/ob_log_insert_all.h"
#include "sql/optimizer/ob_log_err_log.h"
#include "sql/optimizer/ob_insert_log_plan.h"
#include "sql/optimizer/ob_log_stat_collector.h"
#include "share/datum/ob_datum_funcs.h"
#include "share/schema/ob_schema_mgr.h"
#include "sql/engine/ob_operator_factory.h"
#include "sql/engine/basic/ob_limit_op.h"
#include "sql/engine/basic/ob_material_op.h"
#include "sql/engine/basic/ob_count_op.h"
#include "sql/engine/basic/ob_values_op.h"
#include "sql/engine/sort/ob_sort_op.h"
#include "sql/engine/recursive_cte/ob_recursive_union_all_op.h"
#include "sql/engine/set/ob_merge_union_op.h"
#include "sql/engine/set/ob_merge_intersect_op.h"
#include "sql/engine/set/ob_merge_except_op.h"
#include "sql/engine/set/ob_hash_union_op.h"
#include "sql/engine/set/ob_hash_intersect_op.h"
#include "sql/engine/set/ob_hash_except_op.h"
#include "sql/engine/table/ob_table_scan_op.h"
#include "sql/engine/aggregate/ob_hash_distinct_op.h"
#include "sql/engine/aggregate/ob_merge_distinct_op.h"
#include "share/schema/ob_schema_getter_guard.h"
#include "sql/engine/basic/ob_expr_values_op.h"
#include "sql/engine/dml/ob_table_insert_op.h"
#include "sql/engine/expr/ob_expr_column_conv.h"
#include "sql/engine/basic/ob_monitoring_dump_op.h"
#include "sql/engine/px/ob_granule_iterator_op.h"
#include "sql/engine/px/exchange/ob_px_receive_op.h"
#include "sql/engine/px/exchange/ob_px_ms_receive_op.h"
#include "sql/engine/px/exchange/ob_px_dist_transmit_op.h"
#include "sql/engine/px/exchange/ob_px_repart_transmit_op.h"
#include "sql/engine/px/exchange/ob_px_reduce_transmit_op.h"
#include "sql/engine/px/exchange/ob_px_fifo_coord_op.h"
#include "sql/engine/px/exchange/ob_px_ordered_coord_op.h"
#include "sql/engine/px/exchange/ob_px_ms_coord_op.h"
#include "sql/engine/px/ob_px_basic_info.h"
#include "sql/engine/connect_by/ob_nl_cnnt_by_with_index_op.h"
#include "sql/engine/join/ob_hash_join_op.h"
#include "sql/engine/join/ob_nested_loop_join_op.h"
#include "sql/engine/join/ob_join_filter_op.h"
#include "sql/engine/sequence/ob_sequence_op.h"
#include "sql/engine/subquery/ob_subplan_filter_op.h"
#include "sql/engine/subquery/ob_subplan_scan_op.h"
#include "sql/engine/subquery/ob_unpivot_op.h"
#include "sql/engine/expr/ob_expr_subquery_ref.h"
#include "sql/engine/aggregate/ob_scalar_aggregate_op.h"
#include "sql/engine/aggregate/ob_merge_groupby_op.h"
#include "sql/engine/aggregate/ob_hash_groupby_op.h"
#include "sql/engine/join/ob_merge_join_op.h"
#include "sql/engine/basic/ob_topk_op.h"
#include "sql/executor/ob_task_spliter.h"
#include "sql/engine/table/ob_table_lookup_op.h"
#include "sql/engine/dml/ob_table_delete_op.h"
#include "sql/engine/dml/ob_table_merge_op.h"
#include "sql/resolver/dml/ob_merge_stmt.h"
#include "sql/engine/dml/ob_table_update_op.h"
#include "sql/engine/dml/ob_table_lock_op.h"
#include "sql/engine/table/ob_table_row_store_op.h"
#include "sql/engine/dml/ob_table_insert_up_op.h"
#include "sql/engine/dml/ob_table_replace_op.h"
#include "sql/engine/window_function/ob_window_function_op.h"
#include "sql/engine/table/ob_row_sample_scan_op.h"
#include "sql/engine/table/ob_block_sample_scan_op.h"
#include "sql/engine/table/ob_table_scan_with_index_back_op.h"
#include "sql/executor/ob_direct_receive_op.h"
#include "sql/executor/ob_direct_transmit_op.h"
#include "sql/engine/basic/ob_temp_table_access_op.h"
#include "sql/engine/basic/ob_temp_table_insert_op.h"
#include "sql/engine/basic/ob_temp_table_transformation_op.h"
#include "common/ob_smart_call.h"
#include "sql/engine/pdml/static/ob_px_multi_part_delete_op.h"
#include "sql/engine/pdml/static/ob_px_multi_part_insert_op.h"
#include "sql/engine/pdml/static/ob_px_multi_part_update_op.h"
#include "sql/engine/basic/ob_pushdown_filter.h"
#include "observer/omt/ob_tenant_config_mgr.h"
#include "share/schema/ob_schema_utils.h"
#include "sql/engine/pdml/static/ob_px_sstable_insert_op.h"
#include "sql/engine/dml/ob_err_log_op.h"
#include "sql/engine/basic/ob_select_into_op.h"
#include "sql/engine/basic/ob_function_table_op.h"
#include "sql/engine/table/ob_link_scan_op.h"
#include "sql/engine/dml/ob_table_insert_all_op.h"
#include "sql/engine/basic/ob_stat_collector_op.h"
#include "lib/utility/ob_tracepoint.h"
namespace oceanbase
{
using namespace common;
using namespace share;
using namespace share::schema;
namespace sql
{
struct ObFilterTSC
{
bool operator()(const ObOpSpec &spec) const
{
return spec.is_table_scan() && PHY_FAKE_TABLE != spec.type_;
}
};
int ObStaticEngineCG::generate(const ObLogPlan &log_plan, ObPhysicalPlan &phy_plan)
{
int ret = OB_SUCCESS;
phy_plan_ = &phy_plan;
opt_ctx_ = &log_plan.get_optimizer_context();
ObOpSpec *root_spec = NULL;
if (OB_INVALID_ID != log_plan.get_max_op_id()) {
#ifndef NDEBUG
phy_plan.bit_set_.reset();
#endif
phy_plan.set_next_phy_operator_id(log_plan.get_max_op_id());
}
bool need_check_output_datum = false;
ret = E(EventTable::EN_ENABLE_OP_OUTPUT_DATUM_CHECK) ret;
if (OB_FAIL(ret)) {
need_check_output_datum = true;
ret = OB_SUCCESS;
}
const bool in_root_job = true;
const bool is_subplan = false;
bool check_eval_once = true;
if (OB_ISNULL(log_plan.get_plan_root())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("no logical plan root", K(ret));
} else if (OB_FAIL(postorder_generate_op(
*log_plan.get_plan_root(), root_spec, in_root_job, is_subplan,
check_eval_once, need_check_output_datum))) {
LOG_WARN("failed to generate plan", K(ret));
} else if (OB_ISNULL(root_spec)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("generated root spec is NULL", K(ret));
} else {
phy_plan.set_root_op_spec(root_spec);
if (OB_FAIL(set_other_properties(log_plan, phy_plan))) {
LOG_WARN("set other properties failed", K(ret));
}
}
return ret;
}
int ObStaticEngineCG::postorder_generate_op(ObLogicalOperator &op,
ObOpSpec *&spec,
const bool in_root_job,
const bool is_subplan,
bool &check_eval_once,
const bool need_check_output_datum)
{
int ret = OB_SUCCESS;
const int64_t child_num = op.get_num_of_child();
const bool is_exchange = log_op_def::LOG_EXCHANGE == op.get_type();
bool is_link_scan = (log_op_def::LOG_LINK == op.get_type());
spec = NULL;
// generate child first.
ObSEArray<ObOpSpec *, 2> children;
check_eval_once = true;
for (int64_t i = 0; OB_SUCC(ret) && i < child_num && !is_link_scan; i++) {
ObLogicalOperator *child_op = op.get_child(i);
ObOpSpec *child_spec = NULL;
bool child_op_check_eval_once = true;
if (OB_ISNULL(child_op)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("child is NULL", K(ret));
} else if (OB_FAIL(SMART_CALL(postorder_generate_op(*child_op, child_spec,
in_root_job && is_exchange, is_subplan,
child_op_check_eval_once,
need_check_output_datum)))) {
LOG_WARN("generate child op failed", K(ret), K(op.get_name()));
} else if (OB_ISNULL(child_spec)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("generate operator spec is NULL", K(ret));
} else if (OB_FAIL(children.push_back(child_spec))) {
LOG_WARN("array push back failed", K(ret));
} else if (!child_op_check_eval_once) {
// if current op has any dml child op, current op won't check if expr is calculated
check_eval_once = false;
}
}
if(OB_SUCC(ret)
&& (op.is_dml_operator()
|| (log_op_def::LOG_FOR_UPD == op.get_type())
|| (log_op_def::LOG_MERGE == op.get_type()))) {
// if current op is dml child op, it won't check if expr is calculated
check_eval_once = false;
}
// allocate operator spec
ObPhyOperatorType type = PHY_INVALID;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(get_phy_op_type(op, type, in_root_job))) {
LOG_WARN("get phy op type failed", K(ret));
} else if (type == PHY_INVALID || type >= PHY_END) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid phy operator type", K(ret), K(type));
} else if (NULL == phy_plan_
|| OB_FAIL(phy_plan_->alloc_op_spec(
type, children.count(), spec, op.get_op_id()))) {
ret = NULL == phy_plan_ ? OB_INVALID_ARGUMENT : ret;
LOG_WARN("allocate operator spec failed",
K(ret), KP(phy_plan_), K(ob_phy_operator_type_str(type)));
} else if (NULL == spec) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL operator spec returned", K(ret));
} else {
for (int64_t i = 0; i < children.count() && OB_SUCC(ret); i++) {
if (OB_FAIL(spec->set_child(i, children.at(i)))) {
LOG_WARN("set child failed", K(ret));
}
}
}
// Generate operator spec.
// Corresponding ObStaticEngineCG::generate_spec() will be called by
// ObOperatorFactory::generate_spec() if operator registered appropriately
// in ob_operator_reg.h.
// 对于存在subplan的算子, 比如multi part和table lookup算子, 在生成这些原始算子时,
// 嵌套调用postorder_generate_op生成subplan, 此时会将原始算子对应的cur_op_exprs_
// reset掉, 导致原始算子对应的calc_exprs不对, 因此在这里会进行临时备份和复原的处理;
ObSEArray<ObRawExpr *, 8> tmp_cur_op_exprs;
ObSEArray<ObRawExpr *, 8> tmp_cur_op_self_produced_exprs;
if (is_subplan) {
OZ(tmp_cur_op_exprs.assign(cur_op_exprs_));
OZ(tmp_cur_op_self_produced_exprs.assign(cur_op_self_produced_exprs_));
}
cur_op_exprs_.reset();
cur_op_self_produced_exprs_.reset();
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObOperatorFactory::generate_spec(*this, op, *spec, in_root_job))) {
LOG_WARN("generate operator spec failed",
K(ret), KP(phy_plan_), K(ob_phy_operator_type_str(type)));
} else if (OB_FAIL(generate_spec_basic(op, *spec, check_eval_once, need_check_output_datum))) {
LOG_WARN("generate operator spec basic failed", K(ret));
} else if (OB_FAIL(generate_spec_final(op, *spec))) {
LOG_WARN("generate operator spec final failed", K(ret));
} else if (spec->is_dml_operator()) {
ObTableModifySpec *dml_spec = static_cast<ObTableModifySpec *>(spec);
if (dml_spec->use_dist_das()) {
ObExprFrameInfo *partial_frame = OB_NEWx(ObExprFrameInfo, (&phy_plan_->get_allocator()),
phy_plan_->get_allocator(),
phy_plan_->get_expr_frame_info().rt_exprs_);
OV(NULL != partial_frame, OB_ALLOCATE_MEMORY_FAILED);
OZ(ObStaticEngineExprCG::generate_partial_expr_frame(
*phy_plan_, *partial_frame, cur_op_exprs_));
OX(dml_spec->expr_frame_info_ = partial_frame);
}
}
if (is_subplan) {
cur_op_exprs_.reset();
cur_op_self_produced_exprs_.reset();
if (OB_FAIL(cur_op_exprs_.assign(tmp_cur_op_exprs))) {
LOG_WARN("assign exprs failed", K(ret));
} else if (OB_FAIL(cur_op_self_produced_exprs_.assign(tmp_cur_op_self_produced_exprs))) {
LOG_WARN("assign exprs failed", K(ret));
}
}
return ret;
}
int ObStaticEngineCG::check_expr_columnlized(const ObRawExpr *expr)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(ret));
} else if (expr->is_const_or_param_expr()
|| expr->is_const_expr()
|| expr->has_flag(IS_PSEUDO_COLUMN)
|| expr->is_op_pseudo_column_expr()
|| T_MULTI_LOCK_ROWNUM == expr->get_expr_type() // lock_rownum for skip locked is pseudo column
|| T_QUESTIONMARK == expr->get_expr_type()
|| T_CTE_SEARCH_COLUMN == expr->get_expr_type()
|| T_CTE_CYCLE_COLUMN == expr->get_expr_type()
// T_TABLET_AUTOINC_NEXTVAL is the hidden_pk for heap_table
// this column is an pseudo column
|| T_TABLET_AUTOINC_NEXTVAL == expr->get_expr_type()
|| expr->is_set_op_expr()
|| (expr->is_sys_func_expr() && 0 == expr->get_param_count()) // sys func with no param
|| expr->is_query_ref_expr()
|| expr->is_udf_expr()
|| (expr->is_column_ref_expr() && is_shadow_column(static_cast<const ObColumnRefRawExpr*>(expr)->get_column_id()))) {
// skip
} else if ((expr->is_aggr_expr() || (expr->is_win_func_expr()))
&& !expr->has_flag(IS_COLUMNLIZED)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("aggr_expr or win_func_expr should be columnlized", K(ret), KPC(expr));
} else if (!expr->has_flag(IS_COLUMNLIZED)) {
if (0 == expr->get_param_count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr should be columnlized", K(ret), K(expr), KPC(expr));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
if (OB_FAIL(SMART_CALL(check_expr_columnlized(expr->get_param_expr(i))))) {
LOG_WARN("check expr columnlized failed", K(ret), KPC(expr->get_param_expr(i)));
}
}
}
}
return ret;
}
int ObStaticEngineCG::check_exprs_columnlized(ObLogicalOperator &op)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr *, 16> child_outputs;
// clear IS_COLUMNLIZED flag
if (OB_FAIL(clear_all_exprs_specific_flag(cur_op_exprs_, IS_COLUMNLIZED))) {
LOG_WARN("clear all exprs specific flag failed", K(ret));
}
// get all child output exprs
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_num_of_child(); ++i) {
ObLogicalOperator *child_op = op.get_child(i);
if (OB_ISNULL(child_op)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(i));
} else if (OB_FAIL(set_specific_flag_to_exprs(child_op->get_output_exprs(), IS_COLUMNLIZED))) {
LOG_WARN("fail to set specific flag to exprs", K(ret));
}
}
// set IS_COLUMNLIZED flag to child_outputs_exprs and self_produced_exprs
if (OB_SUCC(ret)) {
if (OB_FAIL(set_specific_flag_to_exprs(cur_op_self_produced_exprs_, IS_COLUMNLIZED))) {
LOG_WARN("fail to set specific flag to exprs", K(ret));
}
}
// check if exprs columnlized
for (int64_t i = 0; OB_SUCC(ret) && i < cur_op_exprs_.count(); ++i) {
if (OB_ISNULL(cur_op_exprs_.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(ret));
} else if (OB_FAIL(check_expr_columnlized(cur_op_exprs_.at(i)))) {
LOG_WARN("check expr columnlized failed",
K(ret), K(i), K(cur_op_exprs_.at(i)), KPC(cur_op_exprs_.at(i)));
}
}
return ret;
}
int ObStaticEngineCG::mark_expr_self_produced(ObRawExpr *expr)
{
int ret = OB_SUCCESS;
if (OB_FAIL(cur_op_self_produced_exprs_.push_back(expr))) {
LOG_WARN("push back expr to cur_op_product_exprs_ failed", K(ret), KPC(expr));
}
return ret;
}
int ObStaticEngineCG::mark_expr_self_produced(const ObIArray<ObRawExpr *> &exprs)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) {
if (OB_FAIL(cur_op_self_produced_exprs_.push_back(exprs.at(i)))) {
LOG_WARN("push back expr to cur_op_product_exprs_ failed", K(ret));
}
}
return ret;
}
int ObStaticEngineCG::mark_expr_self_produced(const ObIArray<ObColumnRefRawExpr *> &exprs)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) {
if (OB_FAIL(cur_op_self_produced_exprs_.push_back(exprs.at(i)))) {
LOG_WARN("push back expr to cur_op_product_exprs_ failed", K(ret));
}
}
return ret;
}
int ObStaticEngineCG::set_specific_flag_to_exprs(
const ObIArray<ObRawExpr *> &exprs, ObExprInfoFlag flag)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) {
if (OB_ISNULL(exprs.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(ret), K(i), K(exprs));
} else {
OZ(exprs.at(i)->add_flag(flag));
}
}
return ret;
}
int ObStaticEngineCG::clear_all_exprs_specific_flag(
const ObIArray<ObRawExpr *> &exprs, ObExprInfoFlag flag)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < exprs.count(); ++i) {
if (OB_ISNULL(exprs.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(ret), K(i), K(exprs));
} else {
exprs.at(i)->clear_flag(flag);
}
}
return ret;
}
int ObStaticEngineCG::find_rownum_expr_recursively(bool &found, const ObRawExpr *expr)
{
int ret = OB_SUCCESS;
LOG_DEBUG("find_rownum_expr_recursively begin", K(expr->get_param_count()),
K(expr->get_expr_type()), K(found));
if (expr->get_expr_type() == T_FUN_SYS_ROWNUM) {
found = true;
} else {
for (auto i = 0; !found && i < expr->get_param_count(); i++) {
OZ(SMART_CALL(
find_rownum_expr_recursively(found, expr->get_param_expr(i))));
}
}
LOG_DEBUG("find_rownum_expr_recursively finished", K(expr->get_param_count()),
K(expr->get_expr_type()), K(found));
return ret;
}
int ObStaticEngineCG::find_rownum_expr(
bool &found, const common::ObIArray<ObRawExpr *> &exprs)
{
LOG_DEBUG("find_rownum_expr begin", K(exprs.count()), K(found));
int ret = OB_SUCCESS;
for (auto i = 0; OB_SUCC(ret) && !found && i < exprs.count(); i++) {
ObRawExpr *expr = exprs.at(i);
ret = find_rownum_expr_recursively(found, expr);
LOG_DEBUG(
"find_rownum_expr_recursively done:", K(expr->get_expr_type()),
K(found), K(i), K(expr->get_param_count()));
}
return ret;
}
// rownum expr can show up in the following 4 cases, check them all
// - filter expr
// - output expr
// - join conditions: equal ("=")
// - join conditions: filter (">", "<", ">=", "<=")
int ObStaticEngineCG::find_rownum_expr(bool &found, ObLogicalOperator *op)
{
int ret = OB_SUCCESS;
LOG_DEBUG("find_rownum_expr debug: ", K(op->get_name()), K(found));
if (OB_FAIL(find_rownum_expr(found, op->get_filter_exprs()))) {
LOG_WARN("failure encountered during find rownum expr", K(ret));
} else if (OB_FAIL(find_rownum_expr(found, op->get_output_exprs()))) {
LOG_WARN("failure encountered during find rownum expr", K(ret));
} else if (!found && op->get_type() == log_op_def::LOG_JOIN) {
ObLogJoin *join_op = dynamic_cast<ObLogJoin *>(op);
// NO NPE check for join_op as it should NOT be nullptr
if (OB_FAIL(find_rownum_expr(found, join_op->get_other_join_conditions()))) {
LOG_WARN("failure encountered during find rownum expr", K(ret));
} else if (OB_FAIL(find_rownum_expr(found, join_op->get_equal_join_conditions()))) {
LOG_WARN("failure encountered during find rownum expr", K(ret));
}
}
for (auto i = 0; !found && OB_SUCC(ret) && i < op->get_num_of_child(); i++) {
OZ(SMART_CALL(find_rownum_expr(found, op->get_child(i))));
}
return ret;
}
void ObStaticEngineCG::exprs_not_support_vectorize(const ObIArray<ObRawExpr *> &exprs,
bool &found)
{
FOREACH_CNT_X(e, exprs, !found) {
if (T_ORA_ROWSCN != (*e)->get_expr_type()) {
auto col = static_cast<ObColumnRefRawExpr *>(*e);
if (col->get_result_type().is_urowid()) {
found = true;
} else if (col->get_result_type().is_lob_locator()
|| col->get_result_type().is_lob()
|| col->get_result_type().is_json()) {
found = true;
}
}
}
}
// Enable vectorization as long as one logical operator support vectorization.
// One exception is that if any operator explicitly forbidden vectorization,
// disable vectorization for the whole plan
int ObStaticEngineCG::check_vectorize_supported(bool &support,
bool &stop_checking,
double &scan_cardinality,
ObLogicalOperator *op,
bool is_root_job /* = true */)
{
int ret = OB_SUCCESS;
if (NULL != op) {
ObLogPlan *log_plan = NULL;
ObSqlSchemaGuard *schema_guard = NULL;
const ObTableSchema *table_schema = nullptr;
if (OB_ISNULL(log_plan = op->get_plan()) ||
OB_ISNULL(schema_guard = log_plan->get_optimizer_context().get_sql_schema_guard())) {
support = false;
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid argument", K(op), K(log_plan), K(schema_guard));
} else {
bool disable_vectorize = false;
ObPhyOperatorType type = PHY_INVALID;
if (OB_FAIL(get_phy_op_type(*op, type, is_root_job))) {
LOG_WARN("failed to get_phy_op_type", K(op), K(type));
} else {
if (ObOperatorFactory::is_vectorized(type)) {
support = true;
}
// Additional check to overwrite support value
if (log_op_def::LOG_TABLE_SCAN == op->get_type()) {
// FIXME: bin.lb: disable vectorization for virtual table and virtual column.
auto tsc = static_cast<ObLogTableScan *>(op);
const uint64_t table_id = tsc->get_ref_table_id();
if (is_sys_table(table_id)
|| is_virtual_table(table_id)) {
disable_vectorize = true;
}
if (!support) {
} else if (OB_FAIL(schema_guard->get_table_schema(tsc->get_table_id(), tsc->get_ref_table_id(), op->get_stmt(), table_schema))) {
LOG_WARN("get table schema failed", K(tsc->get_table_id()), K(ret));
} else if (OB_NOT_NULL(table_schema) && 0 < table_schema->get_aux_vp_tid_count()) {
disable_vectorize = true;
}
exprs_not_support_vectorize(tsc->get_access_exprs(), disable_vectorize);
LOG_DEBUG("TableScan base table rows ", K(op->get_card()));
scan_cardinality = common::max(scan_cardinality, op->get_card());
} else if (log_op_def::LOG_TABLE_LOOKUP == op->get_type()) {
auto lookup_op = static_cast<ObLogTableLookup *>(op);
// disable vectorization if certain expressions are found
exprs_not_support_vectorize(lookup_op->get_access_exprs(), disable_vectorize);
} else if (log_op_def::LOG_SUBPLAN_FILTER == op->get_type()) {
auto spf_op = static_cast<ObLogSubPlanFilter *>(op);
if (spf_op->is_update_set()) {
disable_vectorize = true;
}
} else if (log_op_def::LOG_COUNT == op->get_type()) {
// Disable vectorization when rownum expr appears in its children.
// Enabling rownum expression vectorization in LOG_COUNT operator's
// children would generate a batch of rownum with the same value, which
// breaks rownum defination.
// E.G:
// select rownum,a.c1 from t1 a left outer join t1 b on a.c1=b.c1
// and rownum <=b.c1;
//
// Above SQL generates the following plan:
// | ===================================================
// |ID|OPERATOR |NAME|EST. ROWS|COST |
// ---------------------------------------------------
// |0 |COUNT | |32670000 |26856715|
// |1 | HASH RIGHT OUTER JOIN| |32670000 |22347539|
// |2 | TABLE SCAN |B |33334 |78605 |
// |3 | TABLE SCAN |A |100000 |61860 |
// ===================================================
//
// Outputs & filters:
// -------------------------------------
// 0 - output([rownum()], [A.C1]), filter(nil)
// 1 - output([A.C1]), filter(nil),
// equal_conds([A.C1 = B.C1]), other_conds(nil)
// 2 - output([B.C1]), filter([rownum() <= B.C1]),
// access([B.C1]), partitions(p0)
// 3 - output([A.C1]), filter(nil),
// access([A.C1]), partitions(p0)
// bool has_rownum_expr = false;
// Expr rownum() shows up in both operator 0 and 2, which leads circular
// dependency and breaks rownum's defination.
//
bool has_rownum_expr = false;
for (int64_t i = 0; !has_rownum_expr && OB_SUCC(ret) && i < op->get_num_of_child(); i++) {
OZ(find_rownum_expr(has_rownum_expr, op->get_child(i)));
}
if (has_rownum_expr) {
LOG_DEBUG("rownum expr is in count operator's subplan tree. Stop vectorization execution",
K(has_rownum_expr));
disable_vectorize = true;
}
} else if (log_op_def::LOG_JOIN == op->get_type() &&
type == PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX) {
// TODO qubin.qb: support vectorization for connect by with index
disable_vectorize = true;
}
if (OB_SUCC(ret) && !disable_vectorize) {
const ObDMLStmt *stmt = NULL;
if (OB_ISNULL(stmt = op->get_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("dml stmt is null", K(ret));
} else {
const ObIArray<ObUserVarIdentRawExpr *> &user_vars = stmt->get_user_vars();
for (int64_t i = 0; i < user_vars.count() && OB_SUCC(ret); i++) {
const ObUserVarIdentRawExpr *user_var_expr = NULL;
if (OB_ISNULL(user_var_expr = user_vars.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("user var expr is null", K(ret));
} else if (user_var_expr->get_is_contain_assign()) {
disable_vectorize = true;
break;
}
}
}
}
if (disable_vectorize) {
support = false;
stop_checking = true;
}
LOG_DEBUG("check_vectorie_supported", K(disable_vectorize), K(support),
K(op->get_num_of_child()));
// continue searching until found an operator with vectorization explicitly disabled
for (int64_t i = 0; !stop_checking && OB_SUCC(ret) && i < op->get_num_of_child(); i++) {
const bool root = is_root_job && (log_op_def::LOG_EXCHANGE != op->get_type());
OZ(SMART_CALL(check_vectorize_supported(
support, stop_checking, scan_cardinality, op->get_child(i), root)));
}
}
}
}
return ret;
}
// 从raw expr中获取rt_expr,并将raw expr push到cur_op_exprs_中
//
// 设置operater的rt expr, 从raw expr中获取时,均需要通过该接口,
// 其中ObStaticEngineExprCG::generate_rt_expr是ObRawExpr的友元函数, 可直接访问ObRawExpr中rt expr,
//
// 为什么不是ObRawExpr中直接提供访问rt expr的接口给外部使用, 而是用友元函数的方式处理?
//
// 因为在CG过程中,我们需要获取到该operator所有需要生成的表达式(也就是执行时需要的表达式),
// 用于当前operator中calc_expr的生成, 因此通过友元的方式限制对ObRawExpr中rt expr的获取必须使用
// 该接口,并收集到当前operator中所有需要的表达式. 如果ObRawExpr直接提过访问rt expr的接口,
// 其他人在实现operator的表达式cg时,可能直接通过该接口获取rt expr并赋值给operator中对应表达式,
// 这样就没办法收集到完整的当前operator涉及到的表达式, 可能导致结果出错。
//
// 没有直接将ObStaticEngineCG::generate_rt_expr()作为ObRawExpr友元函数原因:
// ob_static_engine_cg.h和ob_raw_expr.h会存在相互依赖, 需要整理依赖关系, 暂时没处理
int ObStaticEngineCG::generate_rt_expr(const ObRawExpr &src, ObExpr *&dst)
{
int ret = OB_SUCCESS;
if (OB_FAIL(ObStaticEngineExprCG::generate_rt_expr(src, cur_op_exprs_, dst))) {
LOG_WARN("fail to push cur op expr", K(ret), K(cur_op_exprs_));
}
return ret;
}
// 从raw expr中获取rt_expr,并将raw expr push到cur_op_exprs_中
int ObStaticEngineCG::generate_rt_exprs(const ObIArray<ObRawExpr *> &src,
ObIArray<ObExpr *> &dst)
{
int ret = OB_SUCCESS;
dst.reset();
if (!src.empty()) {
if (OB_FAIL(dst.reserve(src.count()))) {
LOG_WARN("init fixed array failed", K(ret), K(src.count()));
} else {
FOREACH_CNT_X(raw_expr, src, OB_SUCC(ret)) {
ObExpr *e = NULL;
CK(OB_NOT_NULL(*raw_expr));
OZ(generate_rt_expr(*(*raw_expr), e));
CK(OB_NOT_NULL(e));
OZ(dst.push_back(e));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec_basic(ObLogicalOperator &op,
ObOpSpec &spec,
const bool check_eval_once,
const bool need_check_output_datum)
{
int ret = OB_SUCCESS;
if (0 == spec.rows_) {
spec.rows_ = ceil(op.get_card());
}
spec.cost_ = op.get_cost();
spec.width_ = op.get_width();
spec.plan_depth_ = op.get_plan_depth();
spec.px_est_size_factor_ = op.get_px_est_size_factor();
OZ(generate_rt_exprs(op.get_startup_exprs(), spec.startup_filters_));
if (log_op_def::LOG_TABLE_SCAN == op.get_type() && PHY_FAKE_CTE_TABLE != spec.type_) {
// sanity check table scan type, dynamic_cast is acceptable in CG.
ObLogTableScan *log_tsc = dynamic_cast<ObLogTableScan *>(&op);
ObTableScanSpec *tsc_spec = dynamic_cast<ObTableScanSpec *>(&spec);
CK(NULL != log_tsc);
CK(NULL != tsc_spec);
OZ(tsc_cg_service_.generate_tsc_filter(*log_tsc, *tsc_spec));
} else if (log_op_def::LOG_TABLE_LOOKUP == op.get_type()) {
ObLogTableLookup *log_tlu = dynamic_cast<ObLogTableLookup *>(&op);
ObTableLookupSpec *tlu_spec = dynamic_cast<ObTableLookupSpec *>(&spec);
CK(NULL != log_tlu);
CK(NULL != tlu_spec);
OZ(tsc_cg_service_.generate_table_lookup_filter(*log_tlu, *tlu_spec));
} else if (log_op_def::LOG_SUBPLAN_FILTER == op.get_type() && spec.is_vectorized()) {
ObSubPlanFilterSpec *spf_spec = dynamic_cast<ObSubPlanFilterSpec *>(&spec);
CK(NULL != spf_spec);
OZ(generate_rt_exprs(op.get_filter_exprs(), spf_spec->filter_exprs_));
OZ(generate_rt_exprs(op.get_output_exprs(), spf_spec->output_exprs_));
} else {
OZ(generate_rt_exprs(op.get_filter_exprs(), spec.filters_));
}
OZ(generate_rt_exprs(op.get_output_exprs(), spec.output_));
if (OB_SUCC(ret)) {
if (OB_FAIL(check_exprs_columnlized(op))) {
LOG_WARN("check exprs columnlized failed",
K(ret), K(op.get_name()), K(op.get_op_id()), K(op.get_type()),
K(cur_op_exprs_.count()));
}
}
// 生成calc expr
// 1. 获取所有child operator的output exprs
// 2. 获取当前operator的所有表达式, 并展开
// 3. 将展开后的表达式中不存在于子节点output exprs的计算表达式
// (非T_REF_COLUMN, T_QUESTIONMARK, IS_CONST_LITERAL, 可计算表达式)
// 对应ObExpr添加到calc_exprs_
if (OB_SUCC(ret)) {
// get all child output exprs
ObSEArray<ObRawExpr *, 16> child_outputs;
// table lookup operator don't dependent any output result of child except calc_part_id_expr_
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_num_of_child(); i++) {
ObLogicalOperator *child_op = op.get_child(i);
if (OB_ISNULL(child_op)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(i));
} else if (log_op_def::LOG_TABLE_LOOKUP == op.get_type()) {
for (int64_t j = 0; OB_SUCC(ret) && j < child_op->get_output_exprs().count(); ++j) {
ObRawExpr *expr = child_op->get_output_exprs().at(j);
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (!expr->is_column_ref_expr() &&
OB_FAIL(child_outputs.push_back(expr))) {
LOG_WARN("failed to check child calc part expr", K(ret));
}
}
} else if (OB_FAIL(append(child_outputs, child_op->get_output_exprs()))) {
LOG_WARN("fail to append child exprs", K(ret));
}
} // for end
// when non primary key table partition with generate column;
// main table and index table in table lookup operator has
// common generate expr as output expr,
// for generate column in global index, storage will store data
// for generate column in main table, storage will not store data;
//
// in order to avoid the follow error:
// 1. table lookup generate calc expr will find dependence exprs have been calculated,
// which will report an error;
// 2. if generate column in global index call dependence expr eval, may by core because
// datum of dependence expr may not init by storage;
// the solution is :
// for generate column in global index scan operator, don't need to calc dependence expr,
// and don't flatten generate column when generate calc expr, make the
// dependence expr and generate column self don't add to calc exprs
bool need_flatten_gen_col = !(log_op_def::LOG_TABLE_SCAN == op.get_type()
&& static_cast<ObLogTableScan&>(op).get_is_index_global());
// get calc exprs
OZ(generate_calc_exprs(child_outputs, cur_op_exprs_, spec.calc_exprs_, op.get_type(),
check_eval_once, need_flatten_gen_col),
op.get_op_id(), op.get_name(), K(op.get_type()));
LOG_DEBUG("just for debug, after generate_calc_exprs", K(ret), K(op.get_op_id()), K(op.get_name()), K(op.get_type()));
}
if (OB_SUCC(ret) && need_check_output_datum) {
OZ(add_output_datum_check_flag(spec));
}
return ret;
}
int ObStaticEngineCG::generate_calc_exprs(
const ObIArray<ObRawExpr *> &dep_exprs,
const ObIArray<ObRawExpr *> &cur_exprs,
ObIArray<ObExpr *> &calc_exprs,
const log_op_def::ObLogOpType log_type,
bool check_eval_once,
bool need_flatten_gen_col)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr *, 16> calc_raw_exprs;
ObRawExprUniqueSet flattened_cur_op_exprs(true);
auto filter_func = [&](ObRawExpr *e) { return !has_exist_in_array(dep_exprs, e); };
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(flattened_cur_op_exprs.flatten_and_add_raw_exprs(
cur_exprs, filter_func, need_flatten_gen_col))) {
LOG_WARN("fail to flatten rt exprs", K(ret));
}
const ObIArray<ObRawExpr *> &flattened_cur_exprs_arr = flattened_cur_op_exprs.get_expr_array();
for (int64_t i = 0; OB_SUCC(ret) && i < flattened_cur_exprs_arr.count(); i++) {
ObRawExpr *raw_expr = flattened_cur_exprs_arr.at(i);
CK(OB_NOT_NULL(raw_expr));
bool contain_batch_stmt_parameter = false;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObOptimizerUtil::check_contain_batch_stmt_parameter(
raw_expr,
contain_batch_stmt_parameter))) {
LOG_WARN("failed to check contain batch stmt parameter", K(ret));
} else {
if (!(raw_expr->is_column_ref_expr()
&& !static_cast<ObColumnRefRawExpr *>(raw_expr)->is_virtual_generated_column())
&& !(raw_expr->is_column_ref_expr()
&& static_cast<ObColumnRefRawExpr *>(raw_expr)->is_virtual_generated_column()
&& !need_flatten_gen_col)
&& !raw_expr->is_op_pseudo_column_expr()
&& !has_exist_in_array(dep_exprs, flattened_cur_exprs_arr.at(i))
&& (raw_expr->has_flag(CNT_VOLATILE_CONST)
|| contain_batch_stmt_parameter // 计算包含batch优化的折叠参数
|| !raw_expr->is_const_expr())) {
if (check_eval_once
&& log_op_def::LOG_TABLE_LOOKUP != log_type
&& T_FUN_SYS_ROWNUM != raw_expr->get_expr_type()
&& T_CTE_SEARCH_COLUMN != raw_expr->get_expr_type()
&& T_CTE_CYCLE_COLUMN != raw_expr->get_expr_type()
&& !(raw_expr->is_const_expr() || raw_expr->has_flag(IS_USER_VARIABLE))
// TODO:@guoping.wgp, following T_FUN_SYS_PART restrictions should be removed later
&& !(T_FUN_SYS_PART_HASH == raw_expr->get_expr_type() || T_FUN_SYS_PART_KEY == raw_expr->get_expr_type())) {
if (raw_expr->is_calculated()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is not from the child_op_output but it has been caculated already",
K(ret), K(raw_expr), K(raw_expr->has_flag(CNT_VOLATILE_CONST)), K(raw_expr->is_const_raw_expr()), KPC(raw_expr));
} else {
raw_expr->set_is_calculated(true);
LOG_DEBUG("just for debug, raw_expr->set_is_calculated", K(ret), K(raw_expr), KPC(raw_expr));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(calc_raw_exprs.push_back(raw_expr))) {
LOG_WARN("fail to push output expr", K(ret));
}
}
}
} // for end
if (OB_SUCC(ret) && !calc_raw_exprs.empty()) {
//此次调用会将calc_exprs push到cur_op_exprs_中,实际是无意义的,暂不处理
//因为没有更好的接口来获取ObRawExpr中rt_expr_
if (OB_FAIL(generate_rt_exprs(calc_raw_exprs, calc_exprs))) {
LOG_WARN("fail to append calc exprs", K(ret), K(calc_raw_exprs));
}
}
return ret;
}
// CAUTION: generate_rt_expr()/generate_rt_exprs() can't be invoked in this function,
// because calc_exprs_ is already generated.
int ObStaticEngineCG::generate_spec_final(ObLogicalOperator &op, ObOpSpec &spec)
{
int ret = OB_SUCCESS;
UNUSED(op);
if (PHY_SUBPLAN_FILTER == spec.type_) {
FOREACH_CNT_X(e, spec.calc_exprs_, OB_SUCC(ret)) {
if (T_REF_QUERY == (*e)->type_) {
ObExprSubQueryRef::Extra::get_info(**e).op_id_ = spec.id_;
}
}
}
if (PHY_NESTED_LOOP_CONNECT_BY == spec.type_
|| PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX == spec.type_) {
FOREACH_CNT_X(e, spec.calc_exprs_, OB_SUCC(ret)) {
if (T_OP_PRIOR == (*e)->type_) {
(*e)->extra_ = spec.id_;
}
}
}
// mark insert on dup update scope for T_FUN_SYS_VALUES
if (PHY_INSERT_ON_DUP == spec.type_ || PHY_MULTI_TABLE_INSERT_UP == spec.type_) {
FOREACH_CNT_X(e, spec.calc_exprs_, OB_SUCC(ret)) {
if (T_FUN_SYS_VALUES == (*e)->type_) {
(*e)->extra_ = 1;
}
}
}
if (PHY_TABLE_SCAN == spec.type_ ||
PHY_ROW_SAMPLE_SCAN == spec.type_ ||
PHY_BLOCK_SAMPLE_SCAN == spec.type_) {
ObTableScanSpec &tsc_spec = static_cast<ObTableScanSpec&>(spec);
ObDASScanCtDef &scan_ctdef = tsc_spec.tsc_ctdef_.scan_ctdef_;
ObDASScanCtDef *lookup_ctdef = tsc_spec.tsc_ctdef_.lookup_ctdef_;
if (OB_FAIL(scan_ctdef.pd_expr_spec_.set_calc_exprs(spec.calc_exprs_, tsc_spec.max_batch_size_))) {
LOG_WARN("assign all pushdown exprs failed", K(ret));
} else if (lookup_ctdef != nullptr &&
OB_FAIL(lookup_ctdef->pd_expr_spec_.set_calc_exprs(spec.calc_exprs_, tsc_spec.max_batch_size_))) {
LOG_WARN("assign all pushdown exprs failed", K(ret));
}
}
if (PHY_TABLE_LOOKUP == spec.type_) {
ObTableLookupSpec &tlu_spec = static_cast<ObTableLookupSpec&>(spec);
if (OB_FAIL(tlu_spec.scan_ctdef_.pd_expr_spec_.calc_exprs_.assign(spec.calc_exprs_))) {
LOG_WARN("assign all pushdown expr failed", K(ret));
} else {
tlu_spec.scan_ctdef_.pd_expr_spec_.max_batch_size_ = tlu_spec.max_batch_size_;
}
}
if (log_op_def::LOG_INSERT == op.get_type()) {
auto &insert = static_cast<ObLogInsert&>(op);
phy_plan_->set_is_insert_select(insert.is_insert_select());
} else if (log_op_def::LOG_INSERT_ALL == op.get_type()) {
phy_plan_->set_is_insert_select(true);
}
if (log_op_def::LOG_SET == op.get_type()
&& !static_cast<ObLogSet &>(op).is_recursive_union()
&& spec.is_vectorized()) {
ObSetSpec &set_op = static_cast<ObSetSpec&>(spec);
for (int64_t i = 0; OB_SUCC(ret) && i < set_op.set_exprs_.count(); ++i) {
ObExpr *expr = set_op.set_exprs_.at(i);
if (!expr->is_batch_result()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: set expr is not batch result", K(expr->type_), K(ret));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogLimit &op, ObLimitSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
spec.calc_found_rows_ = op.get_is_calc_found_rows();
spec.is_top_limit_ = op.is_top_limit();
spec.is_fetch_with_ties_ = op.is_fetch_with_ties();
if (NULL != op.get_limit_expr()) {
CK(op.get_limit_expr()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_limit_expr(), spec.limit_expr_));
OZ(mark_expr_self_produced(op.get_limit_expr()));
}
if (NULL != op.get_offset_expr()) {
CK(op.get_offset_expr()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_offset_expr(), spec.offset_expr_));
OZ(mark_expr_self_produced(op.get_offset_expr()));
}
if (NULL != op.get_percent_expr()) {
CK(op.get_percent_expr()->get_result_type().is_double());
OZ(generate_rt_expr(*op.get_percent_expr(), spec.percent_expr_));
OZ(mark_expr_self_produced(op.get_percent_expr()));
}
if (OB_SUCC(ret) && op.is_fetch_with_ties()) {
OZ(spec.sort_columns_.init(op.get_ties_ordering().count()));
FOREACH_CNT_X(it, op.get_ties_ordering(), OB_SUCC(ret)) {
CK(NULL != it->expr_);
ObExpr *e = NULL;
OZ(generate_rt_expr(*it->expr_, e));
OZ(mark_expr_self_produced(it->expr_));
OZ(spec.sort_columns_.push_back(e));
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(
ObLogDistinct &op, ObMergeDistinctSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
spec.by_pass_enabled_ = false;
if (op.get_block_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("merge distinct has no block mode", K(op.get_algo()), K(op.get_block_mode()), K(ret));
} else if (OB_FAIL(spec.cmp_funcs_.init(op.get_distinct_exprs().count()))) {
LOG_WARN("failed to init sort functions", K(ret));
} else if (OB_FAIL(spec.distinct_exprs_.init(op.get_distinct_exprs().count()))) {
LOG_WARN("failed to init distinct exprs", K(ret));
} else {
ObExpr *expr = nullptr;
ARRAY_FOREACH(op.get_distinct_exprs(), i) {
const ObRawExpr* raw_expr = op.get_distinct_exprs().at(i);
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("null pointer", K(ret));
} else if (raw_expr->is_const_expr()) {
// distinct const value, 这里需要注意:distinct 1被跳过了,
// 但ObMergeDistinct中,如果没有distinct列,则默认所有值都相等,这个语义正好是符合预期的。
continue;
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (OB_FAIL(spec.distinct_exprs_.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
} else {
ObCmpFunc cmp_func;
// no matter null first or null last.
cmp_func.cmp_func_ = expr->basic_funcs_->null_last_cmp_;
CK(NULL != cmp_func.cmp_func_);
OZ(spec.cmp_funcs_.push_back(cmp_func));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(
ObLogDistinct &op, ObHashDistinctSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
spec.is_block_mode_ = op.get_block_mode();
spec.is_push_down_ = op.is_push_down();
int64_t init_count = op.get_distinct_exprs().count();
spec.by_pass_enabled_ = (op.is_push_down() && !op.force_push_down());
if (1 != op.get_num_of_child()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected child count of hash distinct", K(ret), K(op.get_num_of_child()));
} else if (OB_FAIL(spec.cmp_funcs_.init(init_count))) {
LOG_WARN("failed to init cmp functions", K(ret));
} else if (OB_FAIL(spec.hash_funcs_.init(init_count))) {
LOG_WARN("failed to init hash functions", K(ret));
} else if (OB_FAIL(spec.sort_collations_.init(init_count))) {
LOG_WARN("failed to init sort functions", K(ret));
} else if (OB_FAIL(spec.distinct_exprs_.init(op.get_distinct_exprs().count()
+ op.get_child(0)->get_output_exprs().count()))) {
LOG_WARN("failed to init distinct exprs", K(ret));
} else {
ObArray<ObRawExpr *> additional_exprs;
ObExpr *expr = nullptr;
ARRAY_FOREACH(op.get_child(0)->get_output_exprs(), i) {
ObRawExpr* raw_expr = op.get_child(0)->get_output_exprs().at(i);
bool is_distinct_expr = has_exist_in_array(op.get_distinct_exprs(), raw_expr);
if (!is_distinct_expr) {
OZ (additional_exprs.push_back(raw_expr));
}
}
if (OB_SUCC(ret)) {
int64_t dist_cnt = 0;
ARRAY_FOREACH(op.get_distinct_exprs(), i) {
ObRawExpr* raw_expr = op.get_distinct_exprs().at(i);
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("null pointer", K(ret));
} else if (raw_expr->is_const_expr()) {
// distinct const value, 这里需要注意:distinct 1被跳过了,
// 但ObMergeDistinct中,如果没有distinct列,则默认所有值都相等,这个语义正好是符合预期的。
continue;
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (OB_FAIL(spec.distinct_exprs_.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
} else if (OB_ISNULL(expr->basic_funcs_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: basic funcs is not init", K(ret));
} else {
ObOrderDirection order_direction = default_asc_direction();
bool is_ascending = is_ascending_direction(order_direction);
ObSortFieldCollation field_collation(dist_cnt,
expr->datum_meta_.cs_type_,
is_ascending,
(is_null_first(order_direction) ^ is_ascending) ? NULL_LAST : NULL_FIRST);
ObCmpFunc cmp_func;
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(
expr->datum_meta_.type_,
expr->datum_meta_.type_,
NULL_LAST,//这里null last还是first无所谓
expr->datum_meta_.cs_type_,
lib::is_oracle_mode());
ObHashFunc hash_func;
hash_func.hash_func_ = expr->basic_funcs_->murmur_hash_;
hash_func.batch_hash_func_ = expr->basic_funcs_->murmur_hash_batch_;
if (OB_ISNULL(cmp_func.cmp_func_) || OB_ISNULL(hash_func.hash_func_)
|| OB_ISNULL(hash_func.batch_hash_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp_func or hash func is null, check datatype is valid",
K(cmp_func.cmp_func_), K(hash_func.hash_func_),
K(hash_func.batch_hash_func_), K(ret));
} else if (OB_FAIL(spec.sort_collations_.push_back(field_collation))) {
LOG_WARN("failed to push back sort collation", K(ret));
} else if (OB_FAIL(spec.cmp_funcs_.push_back(cmp_func))) {
LOG_WARN("failed to push back sort function", K(ret));
} else if (OB_FAIL(spec.hash_funcs_.push_back(hash_func))) {
LOG_WARN("failed to push back hash funcs", K(ret));
} else {
++dist_cnt;
}
}
}
}
// complete distinct exprs
if (OB_SUCC(ret) && 0 != additional_exprs.count()) {
ARRAY_FOREACH(additional_exprs, i) {
const ObRawExpr* raw_expr = additional_exprs.at(i);
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("null pointer", K(ret));
} else if (raw_expr->is_const_expr()) {
// distinct const value, 这里需要注意:distinct 1被跳过了,
// 但ObMergeDistinct中,如果没有distinct列,则默认所有值都相等,这个语义正好是符合预期的。
continue;
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (OB_FAIL(spec.distinct_exprs_.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
}
}
return ret;
}
/*
* Material算子由于本身没有其他额外运行时的变量需要进行处理,所以Codegen时,不需要做任何处理
* 都交给了basic等公共方法弄好了,所以这里实现不需要任何处理,全部为UNUSED
*/
int ObStaticEngineCG::generate_spec(ObLogMaterial &op, ObMaterialSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(op);
UNUSED(spec);
UNUSED(in_root_job);
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogSet &op, ObHashUnionSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_hash_set_spec(op, spec))) {
LOG_WARN("failed to generate spec set", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(
ObLogSet &op, ObHashIntersectSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_hash_set_spec(op, spec))) {
LOG_WARN("failed to generate spec set", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogSet &op, ObHashExceptSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_hash_set_spec(op, spec))) {
LOG_WARN("failed to generate spec set", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_hash_set_spec(ObLogSet &op, ObHashSetSpec &spec)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr *, 4> out_raw_exprs;
if (OB_FAIL(op.extra_set_exprs(out_raw_exprs))) {
LOG_WARN("failed to get output exprs", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(out_raw_exprs))) { // set expr
LOG_WARN("fail to mark exprs self produced", K(ret));
} else if (OB_FAIL(spec.set_exprs_.init(out_raw_exprs.count()))) {
LOG_WARN("failed to init set exprs", K(ret));
} else if (OB_FAIL(generate_rt_exprs(out_raw_exprs, spec.set_exprs_))) {
LOG_WARN("failed to generate rt exprs", K(ret));
} else if (OB_FAIL(spec.sort_collations_.init(spec.set_exprs_.count()))) {
LOG_WARN("failed to init sort collations", K(ret));
} else if (OB_FAIL(spec.sort_cmp_funs_.init(spec.set_exprs_.count()))) {
LOG_WARN("failed to compare function", K(ret));
} else if (OB_FAIL(spec.hash_funcs_.init(spec.set_exprs_.count()))) {
LOG_WARN("failed to compare function", K(ret));
} else {
// 初始化compare func和hash func
for (int64_t i = 0; i < spec.set_exprs_.count() && OB_SUCC(ret); ++i) {
ObRawExpr *raw_expr = out_raw_exprs.at(i);
ObExpr *expr = spec.set_exprs_.at(i);
ObOrderDirection order_direction = default_asc_direction();
bool is_ascending = is_ascending_direction(order_direction);
ObSortFieldCollation field_collation(i,
expr->datum_meta_.cs_type_,
is_ascending,
(is_null_first(order_direction) ^ is_ascending) ? NULL_LAST : NULL_FIRST);
if (raw_expr->get_expr_type() != expr->type_ ||
!(T_OP_SET < expr->type_ && expr->type_ <= T_OP_EXCEPT)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: expr type is not match",
K(raw_expr->get_expr_type()), K(expr->type_));
} else if (OB_ISNULL(expr->basic_funcs_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: basic funcs is not init", K(ret));
} else if (OB_FAIL(spec.sort_collations_.push_back(field_collation))) {
LOG_WARN("failed to push back sort collation", K(ret));
} else {
ObSortCmpFunc cmp_func;
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(expr->datum_meta_.type_,
expr->datum_meta_.type_,
field_collation.null_pos_,
field_collation.cs_type_,
lib::is_oracle_mode());
ObHashFunc hash_func;
hash_func.hash_func_ = expr->basic_funcs_->murmur_hash_;
hash_func.batch_hash_func_ = expr->basic_funcs_->murmur_hash_batch_;
if (OB_ISNULL(cmp_func.cmp_func_) || OB_ISNULL(hash_func.hash_func_)
|| OB_ISNULL(hash_func.batch_hash_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp_func or hash func is null, check datatype is valid",
K(cmp_func.cmp_func_), K(hash_func.hash_func_), K(ret));
} else if (OB_FAIL(spec.sort_cmp_funs_.push_back(cmp_func))) {
LOG_WARN("failed to push back sort function", K(ret));
} else if (OB_FAIL(spec.hash_funcs_.push_back(hash_func))) {
LOG_WARN("failed to push back hash funcs", K(ret));
}
}
}
spec.is_distinct_ = op.is_set_distinct();
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogSet &op, ObMergeUnionSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_merge_set_spec(op, spec))) {
LOG_WARN("failed to generate spec set", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(
ObLogSet &op, ObMergeIntersectSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_merge_set_spec(op, spec))) {
LOG_WARN("failed to generate spec set", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogSet &op, ObMergeExceptSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_merge_set_spec(op, spec))) {
LOG_WARN("failed to generate spec set", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_cte_pseudo_column_row_desc(ObLogSet &op,
ObRecursiveUnionAllSpec &phy_set_op)
{
int ret = OB_SUCCESS;
ObIArray<ObRawExpr *> &output_raw_exprs = op.get_output_exprs();
int64_t column_num = output_raw_exprs.count();
for (int64_t i = 0; OB_SUCC(ret) && i < column_num; ++i) {
if (T_CTE_SEARCH_COLUMN == output_raw_exprs.at(i)->get_expr_type()) {
ObPseudoColumnRawExpr* expr = static_cast<ObPseudoColumnRawExpr*>(output_raw_exprs.at(i));
ObExpr *search_expr = nullptr;
if (OB_FAIL(generate_rt_expr(*expr, search_expr))) {
LOG_WARN("generate rt expr failed", K(ret), KPC(expr));
} else if (OB_FAIL(mark_expr_self_produced(expr))) { // T_CTE_SEARCH_COLUMN
LOG_WARN("mark expr self produced failed", K(ret));
} else if (OB_ISNULL(search_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("rt expr of search expr is null", K(ret));
} else {
phy_set_op.set_search_pseudo_column(search_expr);
}
} else if (T_CTE_CYCLE_COLUMN == output_raw_exprs.at(i)->get_expr_type()) {
ObPseudoColumnRawExpr* expr = static_cast<ObPseudoColumnRawExpr*>(output_raw_exprs.at(i));
ObExpr *cycle_expr = nullptr;
if (OB_FAIL(generate_rt_expr(*expr, cycle_expr))) {
LOG_WARN("generate rt expr failed", K(ret), KPC(expr));
} else if (OB_FAIL(mark_expr_self_produced(expr))) { // T_CTE_CYCLE_COLUMN
LOG_WARN("mark expr self produced failed", K(ret));
} else if (OB_ISNULL(cycle_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("rt expr of cycle expr is null", K(ret));
} else {
phy_set_op.set_cycle_pseudo_column(cycle_expr);
ObRawExpr *v_raw_expr, *d_v_raw_expr;
expr->get_cte_cycle_value(v_raw_expr, d_v_raw_expr);
ObExpr *v_expr, *d_v_expr;
if (OB_ISNULL(v_raw_expr) || OB_ISNULL(d_v_raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Invalid raw expr", K(ret));
} else if (OB_FAIL(generate_rt_expr(*v_raw_expr, v_expr))) {
LOG_WARN("Failed to generate rt expr", K(ret));
} else if (OB_ISNULL(v_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("Invalid expr", K(ret), K(v_expr));
} else if (OB_FAIL(generate_rt_expr(*d_v_raw_expr, d_v_expr))) {
LOG_WARN("Failed to generate rt expr", K(ret));
} else if (OB_ISNULL(d_v_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("Invalid expr", K(ret), K(d_v_expr));
} else if (OB_FAIL(phy_set_op.set_cycle_pseudo_values(v_expr, d_v_expr))) {
LOG_WARN("Failed to set cycle values", K(ret), K(i), K(*expr));
} else {
LOG_DEBUG("Cycle values", K(ret), KPC(v_expr), KPC(d_v_expr), KPC(d_v_raw_expr),
KPC(v_raw_expr));
}
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogSet &op, ObRecursiveUnionAllSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
LOG_DEBUG("static engine cg generate recursive union all", K(spec.get_left()->output_),
K(spec.get_right()->output_), K(op.get_output_exprs()));
if (OB_FAIL(generate_recursive_union_all_spec(op, spec))) {
LOG_WARN("failed to generate spec set", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_merge_set_spec(ObLogSet &op, ObMergeSetSpec &spec)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr *, 4> out_raw_exprs;
if (OB_FAIL(op.extra_set_exprs(out_raw_exprs))) {
LOG_WARN("failed to get output exprs", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(out_raw_exprs))) { // set expr
LOG_WARN("fail to mark exprs self produced", K(ret));
} else if (OB_FAIL(spec.set_exprs_.init(out_raw_exprs.count()))) {
LOG_WARN("failed to init set exprs", K(ret));
} else if (OB_FAIL(generate_rt_exprs(out_raw_exprs, spec.set_exprs_))) {
LOG_WARN("failed to generate rt exprs", K(ret));
} else if (op.is_set_distinct()
&& (spec.set_exprs_.count() != op.get_map_array().count() && 0 != op.get_map_array().count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("output exprs is not match map array", K(ret), K(op.get_map_array().count()),
K(spec.set_exprs_.count()));
} else if (!op.is_set_distinct()) {
} else if (OB_FAIL(spec.sort_collations_.init(spec.set_exprs_.count()))) {
LOG_WARN("failed to init sort collations", K(ret));
} else if (OB_FAIL(spec.sort_cmp_funs_.init(spec.set_exprs_.count()))) {
LOG_WARN("failed to compare function", K(ret));
} else {
for (int64_t i = 0; i < spec.set_exprs_.count() && OB_SUCC(ret); ++i) {
int64_t idx = (0 == op.get_map_array().count()) ? i : op.get_map_array().at(i);
if (idx >= spec.set_exprs_.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: invalid idx", K(idx), K(spec.set_exprs_.count()));
} else {
ObExpr *expr = spec.set_exprs_.at(idx);
ObOrderDirection order_direction = op.get_set_directions().at(i);
bool is_ascending = is_ascending_direction(order_direction);
ObSortFieldCollation field_collation(idx,
expr->datum_meta_.cs_type_,
is_ascending,
(is_null_first(order_direction) ^ is_ascending) ? NULL_LAST : NULL_FIRST);
if (OB_FAIL(spec.sort_collations_.push_back(field_collation))) {
LOG_WARN("failed to push back sort collation", K(ret));
} else {
ObSortCmpFunc cmp_func;
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(expr->datum_meta_.type_,
expr->datum_meta_.type_,
field_collation.null_pos_,
field_collation.cs_type_,
lib::is_oracle_mode());
if (OB_ISNULL(cmp_func.cmp_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp_func is null, check datatype is valid", K(cmp_func.cmp_func_), K(ret));
} else if (OB_FAIL(spec.sort_cmp_funs_.push_back(cmp_func))) {
LOG_WARN("failed to push back sort function", K(ret));
}
}
}
}
}
spec.is_distinct_ = op.is_set_distinct();
return ret;
}
int ObStaticEngineCG::generate_recursive_union_all_spec(ObLogSet &op, ObRecursiveUnionAllSpec &spec)
{
int ret = OB_SUCCESS;
uint64_t last_cte_table_id = OB_INVALID_ID;
ObOpSpec *left = nullptr;
ObOpSpec *right = nullptr;
if (OB_UNLIKELY(spec.get_child_cnt() != 2)
|| OB_ISNULL(left = spec.get_child(0))
|| OB_ISNULL(right = spec.get_child(1))
|| OB_UNLIKELY(left->get_output_count() != right->get_output_count())
|| OB_UNLIKELY(op.get_output_exprs().count() < left->get_output_count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("recursive union all spec should have two children", K(ret), K(spec.get_child_cnt()));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < left->get_output_count(); i++) {
if (left->output_.at(i)->datum_meta_.type_ != left->output_.at(i)->datum_meta_.type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("left and right of recursive union all should have same output data type", K(ret));
}
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(generate_cte_pseudo_column_row_desc(op, spec))) {
LOG_WARN("Failed to generate cte pseudo", K(ret));
} else if (OB_FAIL(fake_cte_tables_.pop_back(last_cte_table_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Failed to pop last cte table op", K(ret), K(&fake_cte_tables_), K(fake_cte_tables_));
} else if (OB_UNLIKELY(OB_INVALID_ID == last_cte_table_id)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Last cte table op cann't be null!", K(ret));
} else {
spec.set_fake_cte_table(last_cte_table_id);
if (op.is_breadth_search()) {
spec.set_search_strategy(ObRecursiveInnerDataOp::SearchStrategyType::BREADTH_FRIST);
} else {
spec.set_search_strategy(ObRecursiveInnerDataOp::SearchStrategyType::DEPTH_FRIST);
}
//recursive union all的输出中的前n项一定是T_OP_UNION,与cte表的非伪列一一对应
OZ(spec.output_union_exprs_.init(left->output_.count()));
ARRAY_FOREACH(left->output_, i)
{
ObRawExpr *output_union_raw_expr = op.get_output_exprs().at(i);
ObExpr *output_union_expr = nullptr;
if (OB_ISNULL(output_union_raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("output expr is null", K(ret), K(i));
} else if (OB_FAIL(generate_rt_expr(*output_union_raw_expr, output_union_expr))) {
LOG_WARN("generate rt expr failed", K(ret));
} else if (OB_ISNULL(output_union_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("output expr is null", K(ret), K(i));
} else if (OB_UNLIKELY(T_OP_UNION != output_union_expr->type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("recursive union all invalid output", K(i), K(*output_union_expr));
} else if (OB_FAIL(mark_expr_self_produced(output_union_raw_expr))) { // set expr
LOG_WARN("fail to mark expr self produced", K(ret));
} else if (OB_FAIL(spec.output_union_exprs_.push_back(output_union_expr))) {
LOG_WARN("array push back failed", K(ret));
}
}
const ObIArray<OrderItem> &search_order = op.get_search_ordering();
OZ(spec.sort_collations_.init(search_order.count()));
ARRAY_FOREACH(search_order, i) {
const ObRawExpr* raw_expr = search_order.at(i).expr_;
if (raw_expr->is_column_ref_expr()) {
const ObColumnRefRawExpr* col_expr = static_cast<const ObColumnRefRawExpr*>(raw_expr);
int64_t sort_idx = col_expr->get_cte_generate_column_projector_offset();
ObOrderDirection order_direction = search_order.at(i).order_type_;
bool is_ascending = is_ascending_direction(order_direction);
ObSortFieldCollation field_collation(sort_idx,
raw_expr->get_collation_type(),
is_ascending,
(is_null_first(order_direction) ^ is_ascending) ? NULL_LAST : NULL_FIRST);
if (OB_FAIL(spec.sort_collations_.push_back(field_collation))) {
LOG_WARN("failed to push back sort collation", K(ret));
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("The search by expr must be cte table column raw expr", K(ret));
}
}
const ObIArray<ColumnItem> &cycle_items = op.get_cycle_items();
OZ(spec.cycle_by_col_lists_.init(cycle_items.count()));
ARRAY_FOREACH(cycle_items, i)
{
const ObRawExpr* raw_expr = cycle_items.at(i).expr_;
if (raw_expr->is_column_ref_expr()) {
uint64_t index = cycle_items.at(i).column_id_;
if (OB_FAIL(spec.cycle_by_col_lists_.push_back(index))) {
LOG_WARN("Failed to add cycle by order", K(ret));
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("The cycle by expr must be cte table column raw expr", K(ret));
}
}
}
return ret;
}
int ObStaticEngineCG::fill_sort_info(
const ObIArray<OrderItem> &sort_keys,
ObSortCollations &collations,
ObIArray<ObExpr*> &sort_exprs)
{
int ret = OB_SUCCESS;
if (OB_FAIL(collations.init(sort_keys.count()))) {
LOG_WARN("failed to init collations", K(ret));
} else {
int64_t start_pos = sort_exprs.count();
for (int64_t i = 0; i < sort_keys.count() && OB_SUCC(ret); ++i) {
const OrderItem &order_item = sort_keys.at(i);
ObExpr *expr = nullptr;
if (order_item.expr_->is_const_expr()) {
LOG_TRACE("trace sort const", K(*order_item.expr_));
continue; // sort by const value, just ignore
} else if (OB_FAIL(generate_rt_expr(*order_item.expr_, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (OB_FAIL(sort_exprs.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
} else {
ObSortFieldCollation field_collation(start_pos++, expr->datum_meta_.cs_type_,
order_item.is_ascending(),
(order_item.is_null_first() ^ order_item.is_ascending()) ? NULL_LAST : NULL_FIRST);
if (OB_FAIL(collations.push_back(field_collation))) {
LOG_WARN("failed to push back field collation", K(ret));
} else {
LOG_DEBUG("succ to push back field collation", K(field_collation), K(start_pos), K(i), K(order_item));
}
}
}
}
return ret;
}
int ObStaticEngineCG::fill_sort_funcs(
const ObSortCollations &collations,
ObSortFuncs &sort_funcs,
const ObIArray<ObExpr*> &sort_exprs)
{
int ret = OB_SUCCESS;
if (OB_FAIL(sort_funcs.init(collations.count()))) {
LOG_WARN("failed to init sort functions", K(ret));
} else {
for (int64_t i = 0; i < collations.count() && OB_SUCC(ret); ++i) {
const ObSortFieldCollation &sort_collation = collations.at(i);
ObExpr* expr = nullptr;
if (OB_FAIL(sort_exprs.at(sort_collation.field_idx_, expr))) {
LOG_WARN("failed to get sort exprs", K(ret));
} else {
ObSortCmpFunc cmp_func;
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(expr->datum_meta_.type_,
expr->datum_meta_.type_,
sort_collation.null_pos_,
sort_collation.cs_type_,
lib::is_oracle_mode());
if (OB_ISNULL(cmp_func.cmp_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp_func is null, check datatype is valid", K(ret));
} else if (OB_FAIL(sort_funcs.push_back(cmp_func))) {
LOG_WARN("failed to push back sort function", K(ret));
}
}
}
}
return ret;
}
/**
* Sort将排序列的ObExpr放在最前面,后面跟output_所有的ObExpr,同时会去重
* all_expr: sort_exprs + output_exprs
**/
int ObStaticEngineCG::generate_spec(ObLogSort &op, ObSortSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
ObSEArray<ObExpr*, 4> output_exprs;
UNUSED(in_root_job);
if (OB_FAIL(generate_rt_exprs(op.get_output_exprs(), output_exprs))) {
LOG_WARN("failed to generate rt exprs", K(ret));
} else {
if (OB_NOT_NULL(op.get_topn_expr())) {
spec.is_fetch_with_ties_ = op.is_fetch_with_ties();
OZ(generate_rt_expr(*op.get_topn_expr(), spec.topn_expr_));
if (OB_NOT_NULL(spec.topn_expr_) && !ob_is_integer_type(spec.topn_expr_->datum_meta_.type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("topn must be int", K(ret), K(*spec.topn_expr_));
}
}
if (OB_NOT_NULL(op.get_topk_limit_expr())) {
OZ(generate_rt_expr(*op.get_topk_limit_expr(), spec.topk_limit_expr_));
if (OB_NOT_NULL(op.get_topk_offset_expr())) {
OZ(generate_rt_expr(*op.get_topk_offset_expr(), spec.topk_offset_expr_));
if (OB_NOT_NULL(spec.topk_offset_expr_)
&& !ob_is_integer_type(spec.topk_offset_expr_->datum_meta_.type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("topn must be int", K(ret), K(*spec.topk_offset_expr_));
}
}
spec.minimum_row_count_ = op.get_minimum_row_count();
spec.topk_precision_ = op.get_topk_precision();
}
if (OB_SUCC(ret)) {
ObSEArray<OrderItem, 1> sortkeys;
if (op.get_part_cnt() > 0 && OB_FAIL(sortkeys.push_back(op.get_hash_sortkey()))) {
LOG_WARN("failed to push back hash sortkey", K(ret));
}
if (OB_FAIL(ret)) {
// do nothing
} else if (op.enable_encode_sortkey_opt()) {
if (OB_FAIL(append(sortkeys, op.get_encode_sortkeys()))) {
LOG_WARN("failed to append encode sortkeys", K(ret));
}
} else {
if (OB_FAIL(append(sortkeys, op.get_sort_keys()))) {
LOG_WARN("failed to append sort key", K(ret));
}
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_ISNULL(spec.get_child())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("child is null", K(ret));
} else if (OB_FAIL(spec.all_exprs_.init(sortkeys.count()
+ spec.get_child()->output_.count()))) {
LOG_WARN("failed to init all exprs", K(ret));
} else if (OB_FAIL(fill_sort_info(sortkeys,
spec.sort_collations_, spec.all_exprs_))) {
LOG_WARN("failed to sort info", K(ret));
} else if (OB_FAIL(fill_sort_funcs(
spec.sort_collations_, spec.sort_cmp_funs_, spec.all_exprs_))) {
LOG_WARN("failed to sort funcs", K(ret));
} else if (OB_FAIL(append_array_no_dup(spec.all_exprs_, spec.get_child()->output_))) {
LOG_WARN("failed to append array no dup", K(ret));
} else {
spec.prefix_pos_ = op.get_prefix_pos();
spec.is_local_merge_sort_ = op.is_local_merge_sort();
if (op.get_plan()->get_optimizer_context().is_online_ddl()) {
spec.prescan_enabled_ = true;
}
spec.enable_encode_sortkey_opt_ = op.enable_encode_sortkey_opt();
spec.part_cnt_ = op.get_part_cnt();
LOG_TRACE("trace order by", K(spec.all_exprs_.count()), K(spec.all_exprs_));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogCount &op, ObCountSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (NULL != op.get_rownum_limit_expr()) {
CK(op.get_rownum_limit_expr()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_rownum_limit_expr(), spec.rownum_limit_));
}
// Anti monotone filters are add to spec.filters_ too in generate_spec_basic(),
// ideally we should only add non_anti_monotone_filters to spec.filters_.
// Since expr evaluating twice is cheap, we add it twice make CG simpler.
if (OB_SUCC(ret) && !op.get_filter_exprs().empty()) {
ObSEArray<ObRawExpr*, 4> anti_monotone_filters;
ObSEArray<ObRawExpr*, 4> non_anti_monotone_filters;
OZ(classify_anti_monotone_filter_exprs(op.get_filter_exprs(),
non_anti_monotone_filters,
anti_monotone_filters));
if (OB_SUCC(ret) && !anti_monotone_filters.empty()) {
OZ(generate_rt_exprs(anti_monotone_filters, spec.anti_monotone_filters_));
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogValues &op,
ObValuesSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(spec.row_store_.assign(op.get_row_store()))) {
LOG_WARN("row store assign failed", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExprValues &op,
ObExprValuesSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (!op.get_value_exprs().empty()) {
spec.contain_ab_param_ = op.contain_array_binding_param();
// 对于insert values(x,x,x)的batch优化场景,折叠参数没当成一个参数视图,contain_ab_param_是false
// 但是为了后续的行为上的一致,还是把contain_ab_param_置为spec.ins_values_batch_opt_
spec.ins_values_batch_opt_ = op.is_ins_values_batch_opt();
if (spec.ins_values_batch_opt_) {
spec.contain_ab_param_ = true;
}
if (OB_FAIL(spec.values_.prepare_allocate(op.get_value_exprs().count()))) {
LOG_WARN("init fixed array failed", K(ret), K(op.get_value_exprs().count()));
} else if (OB_FAIL(spec.str_values_array_.prepare_allocate(op.get_output_exprs().count()))) {
LOG_WARN("init fixed array failed", K(ret), K(op.get_output_exprs().count()));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_value_exprs().count(); i++) {
ObRawExpr *raw_expr = op.get_value_exprs().at(i);
ObExpr *expr = NULL;
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("raw_expr is null", K(ret), K(i), K(raw_expr));
} else if (OB_FAIL(mark_expr_self_produced(raw_expr))) { // expr values
LOG_WARN("mark expr self produced failed", K(ret), KPC(raw_expr));
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("fail to generate_rt_expr", K(ret), K(i), KPC(raw_expr));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("value_info.expr_ is null", K(ret), K(i), KPC(raw_expr));
} else {
spec.values_.at(i) = expr;
}
}
// Add str_values to spec: str_values_ is worked for enum/set type for type conversion.
// According to code in ob_expr_values_op.cpp, it should be in the same order as output_exprs.
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_output_exprs().count(); i++) {
ObRawExpr *output_raw_expr = op.get_output_exprs().at(i);
const common::ObIArray<common::ObString> &str_values = output_raw_expr->get_enum_set_values();
if (!str_values.empty()) {
if (OB_FAIL(spec.str_values_array_.at(i).prepare_allocate(str_values.count()))) {
LOG_WARN("init fixed array failed", K(ret));
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < str_values.count(); ++j) {
if (OB_FAIL(deep_copy_ob_string(phy_plan_->get_allocator(), str_values.at(j),
spec.str_values_array_.at(i).at(j)))) {
LOG_WARN("failed to deep copy string", K(ret), K(str_values));
}
}
}
}
}
LOG_DEBUG("finish assign str_values_array", K(ret), K(spec.str_values_array_));
}
}
if (OB_SUCC(ret)) {
if (0 != op.get_output_exprs().count()) {
spec.rows_ = spec.get_value_count() / op.get_output_exprs().count();
// expr values
if (OB_FAIL(mark_expr_self_produced(op.get_output_exprs()))) {
LOG_WARN("mark expr self produced failed", K(ret));
}
}
}
// cg error logging def
if (OB_FAIL(ret)) {
} else if (OB_FAIL(dml_cg_service_.generate_err_log_ctdef(op.get_err_log_define(), spec.err_log_ct_def_))) {
LOG_WARN("fail to cg err_log_ins_ctdef", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogMerge &op,
ObTableMergeSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_merge_with_das(op, spec, in_root_job))) {
LOG_WARN("fail to generate spec", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_merge_with_das(ObLogMerge &op,
ObTableMergeSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
ObSEArray<uint64_t, 4> modified_index_ids;
const ObMergeStmt *merge_stmt = NULL;
CK(OB_NOT_NULL(op.get_stmt()));
CK(OB_NOT_NULL(op.get_primary_dml_info()));
OZ (op.get_modified_index_id(modified_index_ids));
if (OB_SUCC(ret)) {
merge_stmt = static_cast<const ObMergeStmt*>(op.get_stmt());
spec.has_insert_clause_ = merge_stmt->has_insert_clause();
spec.has_update_clause_ = merge_stmt->has_update_clause();
spec.plan_->need_drive_dml_query_ = true;
spec.use_dist_das_ = op.is_multi_part_dml();
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
spec.table_location_uncertain_ = op.is_table_location_uncertain();
spec.merge_ctdefs_.set_capacity(modified_index_ids.count());
// TODO those 2 line must fixed after remove old engine
OZ(mark_expr_self_produced(op.get_primary_dml_info()->column_exprs_)); // dml columns
for (int64_t i = 0; OB_SUCC(ret) && i < modified_index_ids.count(); ++i) {
ObMergeCtDef *merge_ctdef = nullptr;
if (OB_FAIL(dml_cg_service_.generate_merge_ctdef(op, merge_ctdef, modified_index_ids.at(i)))) {
LOG_WARN("generate insert ctdef failed", K(ret));
} else if (OB_FAIL(spec.merge_ctdefs_.push_back(merge_ctdef))) {
LOG_WARN("store ins ctdef failed", K(ret));
}
} // for index_dml_infos end
}
ObSEArray<ObRawExpr *, 4> rowkeys;
IndexDMLInfo *primary_dml_info = op.get_primary_dml_info();
CK (OB_NOT_NULL(primary_dml_info));
if (OB_SUCC(ret)) {
ObSEArray<ObRawExpr *, 4> distinct_keys;
IndexDMLInfo *primary_dml_info = op.get_primary_dml_info();
if (OB_FAIL(dml_cg_service_.get_table_unique_key_exprs(op,
*primary_dml_info,
distinct_keys))) {
LOG_WARN("get table unique key exprs failed", K(ret), KPC(primary_dml_info));
} else if (OB_FAIL(generate_rt_exprs(distinct_keys, spec.distinct_key_exprs_))) {
LOG_WARN("failed to generate rt exprs", K(ret));
}
}
if (OB_SUCC(ret)) {
OZ(generate_rt_exprs(op.get_update_condition(), spec.update_conds_));
OZ(generate_rt_exprs(op.get_insert_condition(), spec.insert_conds_));
OZ(generate_rt_exprs(op.get_delete_condition(), spec.delete_conds_));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogInsert &op,
ObTableInsertSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_insert_with_das(op, spec))) {
LOG_WARN("generate insert with das failed", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogicalOperator &op,
ObTableRowStoreSpec &spec,
const bool in_root_job)
{
UNUSED(op);
UNUSED(spec);
UNUSED(in_root_job);
return OB_SUCCESS;
}
int ObStaticEngineCG::generate_insert_with_das(ObLogInsert &op, ObTableInsertSpec &spec)
{
int ret = OB_SUCCESS;
const ObIArray<IndexDMLInfo *> &index_dml_infos = op.get_index_dml_infos();
if (OB_ISNULL(phy_plan_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), KP(phy_plan_));
}
if (OB_SUCC(ret) && op.get_stmt_id_expr() != nullptr) {
if (OB_FAIL(generate_rt_expr(*op.get_stmt_id_expr(), spec.ab_stmt_id_))) {
LOG_WARN("generate ab stmt id expr failed", K(ret));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(spec.ins_ctdefs_.allocate_array(phy_plan_->get_allocator(), 1))) {
LOG_WARN("allocate insert ctdef array failed", K(ret), K(1));
} else if (OB_FAIL(spec.ins_ctdefs_.at(0).allocate_array(phy_plan_->get_allocator(),
index_dml_infos.count()))) {
LOG_WARN("allocate insert ctdef array failed", K(ret), K(index_dml_infos.count()));
} else {
spec.plan_->set_ignore(op.is_ignore());
spec.plan_->need_drive_dml_query_ = true;
spec.use_dist_das_ = op.is_multi_part_dml();
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
spec.is_returning_ = op.is_returning();
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < index_dml_infos.count(); ++i) {
const IndexDMLInfo *index_dml_info = index_dml_infos.at(i);
ObInsCtDef *ins_ctdef = nullptr;
if (OB_ISNULL(index_dml_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info is null", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_insert_ctdef(op, *index_dml_info, ins_ctdef))) {
LOG_WARN("generate insert ctdef failed", K(ret));
} else if (OB_ISNULL(ins_ctdef)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ins_ctdef is null", K(ret));
} else {
ins_ctdef->has_instead_of_trigger_ = op.has_instead_of_trigger();
spec.ins_ctdefs_.at(0).at(i) = ins_ctdef;
}
} // for index_dml_infos end
return ret;
}
int ObStaticEngineCG::generate_exprs_replace_spk(const ObIArray<ObColumnRefRawExpr*> &index_exprs,
ObIArray<ObExpr *> &access_exprs) {
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < index_exprs.count(); i ++) {
CK(OB_NOT_NULL(index_exprs.at(i)));
if (OB_SUCC(ret)) {
ObExpr *expr = NULL;
if (is_shadow_column(index_exprs.at(i)->get_column_id())) {
const ObRawExpr *spk_expr = index_exprs.at(i)->get_dependant_expr();
CK(OB_NOT_NULL(spk_expr));
OZ(generate_rt_expr(*spk_expr, expr));
} else { // not shadow column
ObRawExpr *col_expr = index_exprs.at(i);
OZ(generate_rt_expr(*col_expr, expr));
}
OZ(access_exprs.push_back(expr));
}
}
return ret;
}
int ObStaticEngineCG::convert_index_values(uint64_t table_id,
ObIArray<ObExpr*> &output_exprs,
ObOpSpec *&trs_spec)
{
int ret = OB_SUCCESS;
//TODO shengle 处理虚拟列对应calc expr
if (OB_SUCC(ret)) {
OZ(phy_plan_->alloc_op_spec(PHY_TABLE_ROW_STORE,
0,
trs_spec,
OB_INVALID_ID));
OZ(trs_spec->output_.reserve(output_exprs.count()));
FOREACH_CNT_X(expr, output_exprs, OB_SUCC(ret)) {
CK(OB_NOT_NULL(*expr));
OZ(trs_spec->output_.push_back(*expr));
}
if (OB_SUCC(ret)) {
static_cast<ObTableRowStoreSpec *>(trs_spec)->table_id_ = table_id;
}
}
return ret;
}
int ObStaticEngineCG::generate_delete_with_das(ObLogDelete &op, ObTableDeleteSpec &spec)
{
int ret = OB_SUCCESS;
const ObIArray<uint64_t> &delete_table_list = op.get_table_list();
if (OB_ISNULL(phy_plan_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), KP(phy_plan_));
} else {
spec.plan_->set_ignore(op.is_ignore());
spec.plan_->need_drive_dml_query_ = true;
spec.use_dist_das_ = op.is_multi_part_dml();
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
spec.is_returning_ = op.is_returning();
if (OB_FAIL(spec.del_ctdefs_.allocate_array(phy_plan_->get_allocator(),
delete_table_list.count()))) {
LOG_WARN("allocate delete ctdef array failed", K(ret));
}
}
// for batch stmt execute
if (OB_SUCC(ret) && op.get_stmt_id_expr() != nullptr) {
if (OB_FAIL(generate_rt_expr(*op.get_stmt_id_expr(), spec.ab_stmt_id_))) {
LOG_WARN("generate ab stmt id expr failed", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < delete_table_list.count(); ++i) {
const uint64_t loc_table_id = delete_table_list.at(i);
ObSEArray<IndexDMLInfo *, 4> index_delete_infos;
ObTableDeleteSpec::DelCtDefArray &ctdefs = spec.del_ctdefs_.at(i);
if (OB_FAIL(op.get_index_dml_infos(loc_table_id,
index_delete_infos))) {
LOG_WARN("failed to get index dml infos", K(ret));
} else if (OB_FAIL(ctdefs.allocate_array(phy_plan_->get_allocator(),
index_delete_infos.count()))) {
LOG_WARN("allocate delete ctdef array failed", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < index_delete_infos.count(); ++j) {
const IndexDMLInfo *index_dml_info = index_delete_infos.at(j);
ObDelCtDef *del_ctdef = nullptr;
if (OB_ISNULL(index_dml_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info is null", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_delete_ctdef(op, *index_dml_info, del_ctdef))) {
LOG_WARN("generate delete ctdef failed", K(ret));
} else if (OB_ISNULL(del_ctdef)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("del_ctdef is null", K(ret));
} else {
del_ctdef->has_instead_of_trigger_ = op.has_instead_of_trigger();
ctdefs.at(j) = del_ctdef;
}
} // for index_dml_infos end
} //for table_columns end
return ret;
}
// 1、ins_ctdef_->storage_row_output_ 使用的是insert的convert_expr
// 2、del_ctdef_->storage_row_output_ 使用的是column_ref表达式
// 3、spec.table_column_exprs_ 使用的是column_ref表达式
// 4、scan_ctdef_ storage_row_output_ 使用的是column_ref表达式(用于承载回表查询数据)
int ObStaticEngineCG::generate_spec(ObLogInsert &op, ObTableReplaceSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
const ObIArray<IndexDMLInfo *> &insert_dml_infos = op.get_index_dml_infos();;
const ObIArray<IndexDMLInfo *> &del_dml_infos = op.get_replace_index_dml_infos();
const IndexDMLInfo *primary_dml_info = insert_dml_infos.at(0);
CK (NULL != primary_dml_info);
if (OB_SUCC(ret)) {
spec.is_ignore_ = op.is_ignore();
spec.plan_->need_drive_dml_query_ = true;
spec.use_dist_das_ = op.is_multi_part_dml();
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
phy_plan_->set_ignore(op.is_ignore());
// todo @wenber.wb delete it after support trigger
ObLogPlan *log_plan = op.get_plan();
ObSchemaGetterGuard *schema_guard = NULL;
const ObTableSchema *table_schema = NULL;
CK(OB_NOT_NULL(log_plan));
CK(OB_NOT_NULL(schema_guard = log_plan->get_optimizer_context().get_schema_guard()));
OZ(schema_guard->get_table_schema(MTL_ID(), primary_dml_info->ref_table_id_, table_schema));
CK(OB_NOT_NULL(table_schema));
OZ(check_only_one_unique_key(*log_plan, table_schema, spec.only_one_unique_key_));
// 记录当前主表的rowkey的column_ref表达式和column_id
CK(primary_dml_info->column_exprs_.count() == primary_dml_info->column_convert_exprs_.count());
CK(del_dml_infos.count() == insert_dml_infos.count());
OZ(spec.replace_ctdefs_.allocate_array(phy_plan_->get_allocator(), insert_dml_infos.count()));
for (int64_t i = 0; OB_SUCC(ret) && i < insert_dml_infos.count(); ++i) {
const IndexDMLInfo *index_dml_info = insert_dml_infos.at(i);
const IndexDMLInfo *del_index_dml_info = del_dml_infos.at(i);
ObReplaceCtDef *replace_ctdef = nullptr;
if (OB_ISNULL(index_dml_info) || OB_ISNULL(del_index_dml_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info is null", K(ret), K(index_dml_info), K(del_index_dml_info));
} else if (OB_FAIL(dml_cg_service_.generate_replace_ctdef(op,
*index_dml_info,
*del_index_dml_info,
replace_ctdef))) {
LOG_WARN("generate replace ctdef failed", K(ret));
} else if (del_index_dml_info->is_primary_index_) {
if (OB_FAIL(dml_cg_service_.generate_conflict_checker_ctdef(op,
*del_index_dml_info,
spec.conflict_checker_ctdef_))) {
LOG_WARN("generate conflict_checker failed", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(index_dml_info->column_exprs_))) {
LOG_WARN("mark self expr failed", K(ret));
}
}
spec.replace_ctdefs_.at(i) = replace_ctdef;
LOG_DEBUG("print replace_ctdef", K(ret), KPC(replace_ctdef));
} // for index_dml_infos end
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogDelete &op,
ObTableDeleteSpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
int ret = OB_SUCCESS;
ret = generate_delete_with_das(op, spec);
return ret;
}
int ObStaticEngineCG::generate_update_with_das(ObLogUpdate &op, ObTableUpdateSpec &spec)
{
int ret = OB_SUCCESS;
const ObIArray<uint64_t> &table_list = op.get_table_list();
if (OB_ISNULL(phy_plan_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), KP(phy_plan_));
} else {
spec.plan_->set_ignore(op.is_ignore());
spec.plan_->need_drive_dml_query_ = true;
spec.use_dist_das_ = op.is_multi_part_dml();
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
spec.is_returning_ = op.is_returning();
if (OB_FAIL(spec.upd_ctdefs_.allocate_array(phy_plan_->get_allocator(),
table_list.count()))) {
LOG_WARN("allocate update ctdef array failed", K(ret), K(table_list));
}
}
if (OB_SUCC(ret) && op.get_stmt_id_expr() != nullptr) {
if (OB_FAIL(generate_rt_expr(*op.get_stmt_id_expr(), spec.ab_stmt_id_))) {
LOG_WARN("generate ab stmt id expr failed", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < table_list.count(); ++i) {
const uint64_t loc_table_id = table_list.at(i);
ObSEArray<IndexDMLInfo *, 4> index_dml_infos;
ObTableUpdateSpec::UpdCtDefArray &ctdefs = spec.upd_ctdefs_.at(i);
if (OB_FAIL(op.get_index_dml_infos(loc_table_id, index_dml_infos))) {
LOG_WARN("failed to get index dml infos", K(ret));
} else if (OB_FAIL(ctdefs.allocate_array(phy_plan_->get_allocator(), index_dml_infos.count()))) {
LOG_WARN("allocate update ctdef array failed", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < index_dml_infos.count(); ++j) {
const IndexDMLInfo *index_dml_info = index_dml_infos.at(j);
ObUpdCtDef *upd_ctdef = nullptr;
if (OB_ISNULL(index_dml_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info is null", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_update_ctdef(op, *index_dml_info, upd_ctdef))) {
LOG_WARN("generate update ctdef failed", K(ret));
} else if (OB_ISNULL(upd_ctdef)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("upd_ctdef is null", K(ret));
} else {
upd_ctdef->has_instead_of_trigger_ = op.has_instead_of_trigger();
ctdefs.at(j) = upd_ctdef;
}
} // for index_dml_infos end
} //for table_columns end
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogUpdate &op, ObTableUpdateSpec &spec, const bool)
{
int ret = OB_SUCCESS;
CK(typeid(spec) == typeid(ObTableUpdateSpec));
OZ(generate_update_with_das(op, spec));
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogForUpdate &op,
ObTableLockSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
CK(OB_NOT_NULL(op.get_plan()));
spec.use_dist_das_ = op.is_multi_part_dml();
spec.set_is_skip_locked(op.is_skip_locked());
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
spec.for_update_wait_us_ = op.get_wait_ts();
phy_plan_->set_for_update(true);
spec.is_multi_table_skip_locked_ = op.is_multi_table_skip_locked();
if (OB_FAIL(spec.lock_ctdefs_.allocate_array(phy_plan_->get_allocator(),
op.get_index_dml_infos().count()))) {
LOG_WARN("allocate lock ctdef array failed", K(ret), K(op.get_index_dml_infos().count()));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_index_dml_infos().count(); ++i) {
const IndexDMLInfo *index_dml_info = op.get_index_dml_infos().at(i);
ObTableLockSpec::LockCtDefArray &ctdefs = spec.lock_ctdefs_.at(i);
ObLockCtDef *lock_ctdef = nullptr;
if (OB_ISNULL(index_dml_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info is null", K(ret));
} else if (OB_FAIL(ctdefs.allocate_array(phy_plan_->get_allocator(), 1))) {
LOG_WARN("allocate lock ctdef array failed", K(ret), K(index_dml_info));
} else if (OB_FAIL(dml_cg_service_.generate_lock_ctdef(op, *index_dml_info, lock_ctdef))) {
LOG_WARN("generate delete ctdef failed", K(ret));
} else {
ctdefs.at(0) = lock_ctdef;
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogInsert &op, ObTableInsertUpSpec &spec, const bool)
{
int ret = OB_SUCCESS;
if (op.get_index_dml_infos().empty()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("insert dml info is empty", K(ret));
} else if (OB_ISNULL(op.get_index_dml_infos().at(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("insert primary dml info is null", K(ret));
} else if (op.get_insert_up_index_dml_infos().empty()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("update dml info is empty", K(ret));
}
if (OB_SUCC(ret)) {
const ObIArray<IndexDMLInfo *> &insert_dml_infos = op.get_index_dml_infos();
const ObIArray<IndexDMLInfo *> &upd_dml_infos = op.get_insert_up_index_dml_infos();
const IndexDMLInfo *primary_dml_info = insert_dml_infos.at(0);
spec.is_ignore_ = op.is_ignore();
spec.plan_->need_drive_dml_query_ = true;
spec.use_dist_das_ = op.is_multi_part_dml();
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
phy_plan_->set_ignore(op.is_ignore());
ObLogPlan *log_plan = op.get_plan();
ObSchemaGetterGuard *schema_guard = NULL;
const ObTableSchema *table_schema = NULL;
CK (OB_NOT_NULL(log_plan));
CK (OB_NOT_NULL(schema_guard = log_plan->get_optimizer_context().get_schema_guard()));
OZ (schema_guard->get_table_schema(MTL_ID(), primary_dml_info->ref_table_id_, table_schema));
CK (OB_NOT_NULL(table_schema));
OZ(spec.insert_up_ctdefs_.allocate_array(phy_plan_->get_allocator(), insert_dml_infos.count()));
for (int64_t i = 0; OB_SUCC(ret) && i < insert_dml_infos.count(); ++i) {
const IndexDMLInfo *index_dml_info = insert_dml_infos.at(i);
const IndexDMLInfo *upd_dml_info = upd_dml_infos.at(i);
ObInsertUpCtDef *insert_up_ctdef = nullptr;
if (OB_ISNULL(upd_dml_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("update dml info is null", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_insert_up_ctdef(op,
*index_dml_info,
*upd_dml_info,
insert_up_ctdef))) {
LOG_WARN("generate insert ctdef failed", K(ret));
} else {
spec.insert_up_ctdefs_.at(i) = insert_up_ctdef;
LOG_DEBUG("print insert_up_ctdef", KPC(insert_up_ctdef));
}
} // for index_dml_infos end
}
if (OB_SUCC(ret)) {
ObLogicalOperator *child_op = op.get_child(0);
const IndexDMLInfo *upd_pri_dml_info = op.get_insert_up_index_dml_infos().at(0);
const IndexDMLInfo *ins_pri_dml_info = op.get_index_dml_infos().at(0);
if (OB_ISNULL(child_op)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("child_op is null", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_conflict_checker_ctdef(
op,
*upd_pri_dml_info,
spec.conflict_checker_ctdef_))) {
LOG_WARN("generate conflict_checker failed", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(upd_pri_dml_info->column_exprs_))) {
LOG_WARN("mark self expr failed", K(ret));
} else {
common::ObIArray<ObRawExpr *> &child_output_exprs = child_op->get_output_exprs();
ObSEArray<ObRawExpr *, 8> contain_exprs;
ObSEArray<ObRawExpr *, 32> all_need_save_exprs;
for (int i = 0; OB_SUCC(ret) && i < upd_pri_dml_info->assignments_.count(); i++) {
ObRawExpr *raw_expr = upd_pri_dml_info->assignments_.at(i).expr_;
if (OB_FAIL(ObRawExprUtils::extract_contain_exprs(raw_expr,
child_output_exprs,
contain_exprs))) {
LOG_WARN("fail to extract contain exprs", K(ret));
} else {
LOG_DEBUG("print one contain_exprs", KPC(raw_expr) ,K(child_output_exprs), K(contain_exprs));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(append(all_need_save_exprs, ins_pri_dml_info->column_convert_exprs_))) {
LOG_WARN("fail to append expr to array", K(ret));
} else if (OB_FAIL(append(all_need_save_exprs, contain_exprs))) {
LOG_WARN("fail to append expr to array", K(ret));
} else if (OB_FAIL(generate_rt_exprs(all_need_save_exprs, spec.all_saved_exprs_))) {
LOG_WARN("fail to generate all_saved_expr", K(ret), K(all_need_save_exprs));
} else {
LOG_DEBUG("print all_need_save_exprs", K(all_need_save_exprs));
}
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTopk &op,
ObTopKSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
CK(typeid(spec) == typeid(ObTopKSpec));
if (NULL != op.get_topk_limit_count()) {
CK(op.get_topk_limit_count()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_topk_limit_count(), spec.org_limit_));
}
if (NULL != op.get_topk_limit_offset()) {
CK(op.get_topk_limit_offset()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_topk_limit_offset(), spec.org_offset_));
}
OX(spec.minimum_row_count_ = op.get_minimum_row_count());
OX(spec.topk_precision_ = op.get_topk_precision());
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogSequence &op, ObSequenceSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(spec.nextval_seq_ids_.init(op.get_sequence_ids().count()))) {
LOG_WARN("failed to init sequence indexes", K(ret));
} else {
const ObIArray<uint64_t> &ids = op.get_sequence_ids();
ARRAY_FOREACH_X(ids, idx, cnt, OB_SUCC(ret)) {
if (OB_FAIL(spec.add_uniq_nextval_sequence_id(ids.at(idx)))) {
LOG_WARN("failed to set sequence", K(ids), K(ret));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogMonitoringDump &op, ObMonitoringDumpSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
spec.flags_ = op.get_flags();
spec.dst_op_id_ = op.get_dst_op_id();
// monitoring dump op check output datum always.
if (spec.is_vectorized()) {
spec.need_check_output_datum_ = true;
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogJoinFilter &op, ObJoinFilterSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
spec.set_mode(op.is_create_filter() ? JoinFilterMode::CREATE : JoinFilterMode::USE);
spec.set_filter_id(op.get_filter_id());
spec.set_server_id(GCTX.server_id_);
spec.set_filter_length(op.get_filter_length());
spec.set_is_shuffle(op.is_use_filter_shuffle());
spec.set_filter_type(op.get_filter_type());
if (OB_FAIL(spec.join_keys_.init(op.get_join_exprs().count()))) {
LOG_WARN("failed to init join keys", K(ret));
} else if (OB_NOT_NULL(op.get_tablet_id_expr()) &&
OB_FAIL(generate_calc_part_id_expr(*op.get_tablet_id_expr(), nullptr, spec.calc_tablet_id_expr_))) {
LOG_WARN("fail to generate calc part id expr", K(ret), KP(op.get_tablet_id_expr()));
} else if (OB_FAIL(spec.hash_funcs_.init(op.get_join_exprs().count()))) {
LOG_WARN("failed to init join keys", K(ret));
} else if (OB_FAIL(generate_rt_exprs(op.get_join_exprs(), spec.join_keys_))) {
LOG_WARN("failed to generate rt exprs", K(ret));
} else {
if (OB_NOT_NULL(spec.calc_tablet_id_expr_)) {
ObHashFunc hash_func;
hash_func.hash_func_ = spec.calc_tablet_id_expr_->basic_funcs_->murmur_hash_;
hash_func.batch_hash_func_ = spec.calc_tablet_id_expr_->basic_funcs_->murmur_hash_batch_;
if (OB_FAIL(spec.hash_funcs_.push_back(hash_func))) {
LOG_WARN("failed to push back hash func", K(ret));
}
} else {
bool is_new_hash_version = (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_4_0_0_0);
for (int64_t i = 0; i < spec.join_keys_.count() && OB_SUCC(ret); ++i) {
ObExpr *join_expr = spec.join_keys_.at(i);
ObHashFunc hash_func;
if (is_new_hash_version) {
hash_func.hash_func_ = join_expr->basic_funcs_->murmur_hash_;
hash_func.batch_hash_func_ = join_expr->basic_funcs_->murmur_hash_batch_;
} else {
hash_func.hash_func_ = join_expr->basic_funcs_->default_hash_;
hash_func.batch_hash_func_ = join_expr->basic_funcs_->default_hash_batch_;
}
if (OB_ISNULL(hash_func.hash_func_) || OB_ISNULL(hash_func.batch_hash_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("hash func is null, check datatype is valid", K(ret));
} else if (OB_FAIL(spec.hash_funcs_.push_back(hash_func))) {
LOG_WARN("failed to push back hash func", K(ret));
}
}
}
}
if (OB_SUCC(ret) && !op.is_create_filter()) {
ObExpr *join_filter_expr = nullptr;
if (OB_ISNULL(op.get_join_filter_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("join filter expr is null", K(ret));
} else if (OB_ISNULL(join_filter_expr =
reinterpret_cast<ObExpr *>(
ObStaticEngineExprCG::get_left_value_rt_expr(*op.get_join_filter_expr())))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("join filter rt_expr_ is null", K(ret));
} else {
spec.filter_expr_id_ = join_filter_expr->expr_ctx_id_;
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogGranuleIterator &op, ObGranuleIteratorSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
ObLogicalOperator *child_log_op = op.get_child(0);
spec.set_tablet_size(op.get_tablet_size());
spec.set_gi_flags(op.get_gi_flags());
if (log_op_def::LOG_TABLE_SCAN == child_log_op->get_type()) {
ObLogTableScan *log_tsc = NULL;
log_tsc = static_cast<ObLogTableScan*>(child_log_op);
//这里拿ref_table_id的行为是为了和table scan拿partition service的行为一致
spec.set_related_id(log_tsc->get_ref_table_id());
}
ObPhyPlanType execute_type = spec.plan_->get_plan_type();
if (execute_type == OB_PHY_PLAN_LOCAL) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("not supported at this time", K(ret));
} else if (op.get_join_filter_info().is_inited_) {
spec.bf_info_ = op.get_join_filter_info();
if (OB_ISNULL(op.get_tablet_id_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("op is null", K(ret));
} else if (OB_FAIL(generate_calc_part_id_expr(*op.get_tablet_id_expr(), nullptr, spec.tablet_id_expr_))) {
LOG_WARN("generate calc part id expr failed", K(ret));
} else {
spec.hash_func_.hash_func_ = spec.tablet_id_expr_->basic_funcs_->murmur_hash_;
spec.hash_func_.batch_hash_func_ = spec.tablet_id_expr_->basic_funcs_->murmur_hash_batch_;
}
}
LOG_TRACE("convert gi operator", K(ret),
"tablet size", op.get_tablet_size(),
"affinitize", op.access_all(),
"pwj gi", op.pwj_gi(),
"param down", op.with_param_down(),
"asc", op.asc_order(),
"desc", op.desc_order(),
"flags", op.get_gi_flags());
return ret;
}
int ObStaticEngineCG::check_rollup_distributor(ObPxTransmitSpec *spec)
{
int ret = OB_SUCCESS;
if (spec->is_rollup_hybrid_) {
ObOpSpec *root = spec->get_child(0);
while (OB_NOT_NULL(root) && OB_SUCC(ret)) {
if (ObPhyOperatorType::PHY_MONITORING_DUMP == root->type_) {
root = root->get_child(0);
} else if (ObPhyOperatorType::PHY_MATERIAL == root->type_) {
root = root->get_child(0);
} else if (ObPhyOperatorType::PHY_MERGE_GROUP_BY == root->type_) {
break;
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: invalid operator type", K(ret), K(root->type_));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_basic_transmit_spec(
ObLogExchange &op, ObPxTransmitSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (!op.is_producer()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: it's not producer", K(ret));
} else {
if (op.get_is_remote()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: produce is remote", K(ret));
} else {
int spliter_type = ObTaskSpliter::INVALID_SPLIT;
switch (spec.get_child()->get_type()) {
case PHY_INSERT:
case PHY_REPLACE:
case PHY_INSERT_ON_DUP:
spliter_type = ObTaskSpliter::INSERT_SPLIT;
break;
default:
spliter_type = ObTaskSpliter::DISTRIBUTED_SPLIT;
break;
}
spec.set_split_task_count(op.get_slice_count());
spec.set_parallel_server_count(1);
spec.set_server_parallel_thread_count(1);
// spec.get_job_conf().set_task_split_type(spliter_type);
spec.repartition_type_ = op.get_repartition_type();
spec.repartition_ref_table_id_ = op.get_repartition_ref_table_id();
spec.dist_method_ = op.get_dist_method();
spec.unmatch_row_dist_method_ = op.get_unmatch_row_dist_method();
spec.null_row_dist_method_ = op.get_null_row_dist_method();
spec.set_px_single(op.is_px_single());
spec.set_px_dop(op.get_parallel());
spec.set_px_id(op.get_px_id());
spec.set_dfo_id(op.get_dfo_id());
spec.set_slave_mapping_type(op.get_slave_mapping_type());
spec.need_null_aware_shuffle_ = op.need_null_aware_shuffle();
spec.is_rollup_hybrid_ = op.is_rollup_hybrid();
spec.sample_type_ = op.get_sample_type();
spec.repartition_table_id_ = op.get_repartition_table_id();
OZ(check_rollup_distributor(&spec));
LOG_TRACE("CG transmit", K(op.get_dfo_id()), K(op.get_op_id()),
K(op.get_dist_method()), K(op.get_unmatch_row_dist_method()));
}
}
// 处理PDML partition_id 伪列
if (OB_SUCC(ret)) {
// 仅仅处理repart情况
if (spec.type_ == PHY_PX_REPART_TRANSMIT) {
if (NULL != op.get_partition_id_expr()) {
OZ(generate_rt_expr(*op.get_partition_id_expr(), spec.tablet_id_expr_));
}
}
}
if (NULL != op.get_random_expr()) {
OZ(generate_rt_expr(*op.get_random_expr(), spec.random_expr_));
}
if (OB_SUCC(ret) &&
(ObPQDistributeMethod::PARTITION_RANGE == op.get_dist_method()
|| ObPQDistributeMethod::RANGE == op.get_dist_method())) {
ObSEArray<ObExpr *, 16> sampling_saving_row;
OZ(append(sampling_saving_row, spec.get_child()->output_));
if (NULL != spec.random_expr_) {
OZ(sampling_saving_row.push_back(spec.random_expr_));
}
OZ(spec.sampling_saving_row_.assign(sampling_saving_row));
}
return ret;
}
int ObStaticEngineCG::generate_basic_receive_spec(ObLogExchange &op, ObPxReceiveSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if ((in_root_job || op.is_rescanable()) && op.is_sort_local_order()) {
// root节点不会出现需要local order的exchange-in
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected plan that has merge sort receive with local order in root job", K(ret));
} else {
spec.repartition_table_id_ = op.get_repartition_table_id();
if (OB_FAIL(spec.child_exprs_.init(spec.get_child()->output_.count()))) {
LOG_WARN("failed to init child exprs", K(ret));
} else if (spec.bloom_filter_id_array_.assign(op.get_bloom_filter_ids())) {
LOG_WARN("failed to append bloom filter ids", K(ret));
} else if (OB_FAIL(spec.child_exprs_.assign(spec.get_child()->output_))) {
LOG_WARN("failed to append child exprs", K(ret));
} else if (OB_FAIL(init_recieve_dynamic_exprs(spec.get_child()->output_, spec))) {
LOG_WARN("fail to init recieve dynamic expr", K(ret));
} else if (IS_PX_COORD(spec.get_type())) {
ObPxCoordSpec *coord = static_cast<ObPxCoordSpec*>(&spec);
coord->set_expected_worker_count(op.get_expected_worker_count());
const ObTransmitSpec *transmit_spec = static_cast<const ObTransmitSpec*>(spec.get_child());
coord->qc_id_ = transmit_spec->get_px_id();
if (op.get_px_batch_op_id() != OB_INVALID_ID) {
if (log_op_def::LOG_JOIN == op.get_px_batch_op_type()) {
coord->set_px_batch_op_info(op.get_px_batch_op_id(), PHY_NESTED_LOOP_JOIN);
} else if (log_op_def::LOG_SUBPLAN_FILTER == op.get_px_batch_op_type()) {
coord->set_px_batch_op_info(op.get_px_batch_op_id(), PHY_SUBPLAN_FILTER);
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("batch op type is unexpected", K(ret), K(op.get_px_batch_op_type()));
}
}
if (OB_SUCC(ret) && GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_2276) {
if (OB_FAIL(coord->get_table_locations().prepare_allocate(op.get_pruning_table_locations().count(),
phy_plan_->get_allocator()))) {
LOG_WARN("fail to init pruning table locations", K(ret));
} else {
for (int i = 0; i < op.get_pruning_table_locations().count() && OB_SUCC(ret); ++i) {
OZ(coord->get_table_locations().at(i).assign(op.get_pruning_table_locations().at(i)));
}
}
}
LOG_TRACE("map worker to px coordinator", K(spec.get_type()),
"id", op.get_op_id(),
"count", op.get_expected_worker_count());
}
}
return ret;
}
int ObStaticEngineCG::init_recieve_dynamic_exprs(const ObIArray<ObExpr *> &child_outputs,
ObPxReceiveSpec &spec)
{
int ret = OB_SUCCESS;
ObSEArray<ObExpr *, 2> dynamic_consts;
for (int64_t i = 0; OB_SUCC(ret) && i < child_outputs.count(); i++) {
if (child_outputs.at(i)->is_dynamic_const_ && !child_outputs.at(i)->is_static_const_) {
OZ(dynamic_consts.push_back(child_outputs.at(i)));
}
}
OZ(spec.dynamic_const_exprs_.assign(dynamic_consts));
return ret;
}
// 目前都是假设receive和transmit数据列一致,如果不一致,则拿receive收transmit数据就需要根据child exprs来拿数据
// 暂时取消这种假设,所以需要额外的child_exprs来获取dtl传过来的数据
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxFifoReceiveSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_receive_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic receive spec", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxMSCoordSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_receive_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic receive spec", K(ret));
} else if (OB_FAIL(spec.all_exprs_.init(op.get_sort_keys().count() + spec.child_exprs_.count()))) {
LOG_WARN("failed to init all exprs", K(ret));
} else if (OB_FAIL(fill_sort_info(op.get_sort_keys(),
spec.sort_collations_, spec.all_exprs_))) {
LOG_WARN("failed to sort info", K(ret));
} else if (OB_FAIL(fill_sort_funcs(
spec.sort_collations_, spec.sort_cmp_funs_, spec.all_exprs_))) {
LOG_WARN("failed to sort funcs", K(ret));
} else if (OB_FAIL(append_array_no_dup(spec.all_exprs_, spec.child_exprs_))) {
LOG_WARN("failed to append array no dup", K(ret));
} else {
spec.is_old_unblock_mode_ = op.is_old_unblock_mode();
LOG_TRACE("trace merge sort coord", K(spec.is_old_unblock_mode_));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObDirectTransmitSpec &spec, const bool in_root_job)
{
// do nothing
UNUSED(op);
UNUSED(spec);
UNUSED(in_root_job);
return OB_SUCCESS;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObDirectReceiveSpec &spec, const bool in_root_job)
{
// do nothing
UNUSED(op);
UNUSED(spec);
UNUSED(in_root_job);
return OB_SUCCESS;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxMSReceiveSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_receive_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic receive spec", K(ret));
} else if (OB_FAIL(spec.all_exprs_.init(op.get_sort_keys().count() + spec.child_exprs_.count()))) {
LOG_WARN("failed to init all exprs", K(ret));
} else if (OB_FAIL(fill_sort_info(op.get_sort_keys(),
spec.sort_collations_, spec.all_exprs_))) {
LOG_WARN("failed to sort info", K(ret));
} else if (OB_FAIL(fill_sort_funcs(
spec.sort_collations_, spec.sort_cmp_funs_, spec.all_exprs_))) {
LOG_WARN("failed to sort funcs", K(ret));
} else if (OB_FAIL(append_array_no_dup(spec.all_exprs_, spec.child_exprs_))) {
LOG_WARN("failed to append array no dup", K(ret));
} else {
spec.local_order_ = op.is_sort_local_order();
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxDistTransmitSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_transmit_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic transmit spec", K(ret));
} else if (OB_FAIL(generate_hash_func_exprs(op.get_hash_dist_exprs(),
spec.dist_exprs_,
spec.dist_hash_funcs_))) {
LOG_WARN("fail generate hash func exprs", K(ret));
} else if (op.is_pq_range() && OB_FAIL(generate_range_dist_spec(op, spec))) {
LOG_WARN("fail to generate range dist", K(ret));
} else if (ObPQDistributeMethod::PARTITION_HASH == op.get_dist_method()
|| ObPQDistributeMethod::SM_BROADCAST == op.get_dist_method()) {
if (OB_ISNULL(op.get_calc_part_id_expr())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("slave mapping pk_hash's calc_part_id_expr is null", K(ret));
} else if (OB_FAIL(generate_calc_part_id_expr(*op.get_calc_part_id_expr(), nullptr, spec.calc_tablet_id_expr_))) {
LOG_WARN("fail to generate calc part id expr", K(ret), KP(op.get_calc_part_id_expr()));
}
}
return ret;
}
int ObStaticEngineCG::generate_hash_func_exprs(
const common::ObIArray<ObExchangeInfo::HashExpr> &hash_dist_exprs,
ExprFixedArray &dist_exprs,
common::ObHashFuncs &dist_hash_funcs)
{
int ret = OB_SUCCESS;
if (OB_FAIL(dist_exprs.init(hash_dist_exprs.count()))) {
LOG_WARN("failed to init dist exprs", K(ret));
} else if (OB_FAIL(dist_hash_funcs.init(hash_dist_exprs.count()))) {
LOG_WARN("failed to init dist exprs", K(ret));
} else {
ObExpr *dist_expr = nullptr;
FOREACH_CNT_X(expr, hash_dist_exprs, OB_SUCC(ret)) {
if (OB_ISNULL(expr->expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL expr", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(expr->expr_))) {
LOG_WARN("failed to add columnized flag", K(ret));
} else if (OB_FAIL(generate_rt_expr(*expr->expr_, dist_expr))) {
LOG_WARN("generate expr failed", K(ret));
} else if (OB_FAIL(dist_exprs.push_back(dist_expr))) {
LOG_WARN("failed to push back expr", K(ret));
} else {
ObHashFunc hash_func;
hash_func.hash_func_ = dist_expr->basic_funcs_->murmur_hash_;
hash_func.batch_hash_func_ = dist_expr->basic_funcs_->murmur_hash_batch_;
if (OB_ISNULL(hash_func.hash_func_) || OB_ISNULL(hash_func.batch_hash_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("hash func is null, check datatype is valid", K(ret));
} else if (OB_FAIL(dist_hash_funcs.push_back(hash_func))) {
LOG_WARN("failed to push back hash function", K(ret));
}
}
}
}
return ret;
}
int ObStaticEngineCG::generate_range_dist_spec(
ObLogExchange &op,
ObPxDistTransmitSpec &spec)
{
int ret = OB_SUCCESS;
ObArray<OrderItem> new_sort_keys;
if (OB_FAIL(filter_sort_keys(op, op.get_sort_keys(), new_sort_keys))) {
LOG_WARN("filter sort keys failed", K(ret));
} else if (OB_FAIL(spec.dist_exprs_.init(new_sort_keys.count()))) {
LOG_WARN("failed to init all exprs", K(ret));
} else if (OB_FAIL(fill_sort_info(new_sort_keys,
spec.sort_collations_, spec.dist_exprs_))) {
LOG_WARN("failed to sort info", K(ret));
} else if (OB_FAIL(fill_sort_funcs(spec.sort_collations_,
spec.sort_cmp_funs_, spec.dist_exprs_))) {
LOG_WARN("failed to sort funcs", K(ret));
}
return ret;
}
int ObStaticEngineCG::filter_sort_keys(
ObLogExchange &op,
const ObIArray<OrderItem> &old_sort_keys,
ObIArray<OrderItem> &new_sort_keys)
{
int ret = OB_SUCCESS;
// filter out partition id expr
for (int64_t i = 0; OB_SUCC(ret) && i < old_sort_keys.count(); ++i) {
ObRawExpr *cur_expr = old_sort_keys.at(i).expr_;
if (OB_ISNULL(cur_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("current raw expr is null", K(ret), K(i), KP(cur_expr));
} else if (cur_expr->is_calc_part_expr()
|| ObItemType::T_PSEUDO_CALC_PART_SORT_KEY == cur_expr->get_expr_type()) {
// filter out
} else if (OB_FAIL(new_sort_keys.push_back(old_sort_keys.at(i)))) {
LOG_WARN("push back order item failed", K(ret), K(i));
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxRepartTransmitSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_transmit_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic transmit spec", K(ret));
} else if (OB_ISNULL(op.get_calc_part_id_expr())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("repart_transmit's calc_part_id_expr is null", K(ret));
} else if (OB_FAIL(generate_calc_part_id_expr(*op.get_calc_part_id_expr(), nullptr, spec.calc_tablet_id_expr_))) {
LOG_WARN("fail to generate calc part id expr", K(ret), KP(op.get_calc_part_id_expr()));
}
// for pkey-hash, need add hash expr
if (OB_SUCC(ret) && op.get_hash_dist_exprs().count() > 0) {
if (OB_FAIL(generate_hash_func_exprs(op.get_hash_dist_exprs(),
spec.dist_exprs_,
spec.dist_hash_funcs_))) {
LOG_WARN("fail generate hash func exprs", K(ret));
}
}
if (OB_SUCC(ret)) {
// repartition_exprs_ only use by null aware anti join
// now just support single join key
// either repart_keys or repart_sub_keys exists join key
// so we can generate from one of them driectly
if (op.get_repart_keys().count() > 0) {
if (OB_FAIL(generate_rt_exprs(op.get_repart_keys(), spec.repartition_exprs_))) {
LOG_WARN("failed to generate repart exprs", K(ret));
}
} else if (op.get_repart_sub_keys().count() > 0) {
if (OB_FAIL(generate_rt_exprs(op.get_repart_sub_keys(), spec.repartition_exprs_))) {
LOG_WARN("failed to generate repart exprs", K(ret));
}
}
}
// for pkey-range, generate spec of sort columns
if (OB_SUCC(ret) && ObPQDistributeMethod::PARTITION_RANGE == op.get_dist_method()) {
ObArray<OrderItem> sort_keys;
if (OB_FAIL(filter_sort_keys(op, op.get_sort_keys(), sort_keys))) {
LOG_WARN("filter out expr of partition id failed", K(ret));
} else if (OB_FAIL(spec.dist_exprs_.reserve(sort_keys.count()))) {
LOG_WARN("init dist exprs failed", K(ret));
} else if (OB_FAIL(fill_sort_info(sort_keys, spec.sort_collations_, spec.dist_exprs_))) {
LOG_WARN("fill sort info failed", K(ret));
} else if (OB_FAIL(fill_sort_funcs(spec.sort_collations_, spec.sort_cmp_funs_, spec.dist_exprs_))) {
LOG_WARN("fill sort funcs failed", K(ret));
} else if (OB_UNLIKELY(op.get_repart_all_tablet_ids().count() <= 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid partition ids", K(ret), K(op.get_repart_all_tablet_ids().count()));
} else if (OB_FAIL(spec.ds_tablet_ids_.assign(op.get_repart_all_tablet_ids()))) {
LOG_WARN("assign partition ids failed", K(ret), K(op.get_repart_all_tablet_ids()));
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxReduceTransmitSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_transmit_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic transmit spec", K(ret));
}
return ret;
}
// dynamic sample use data hub model and px coord is the hub.
// so generate spec for dynamic sample if need
int ObStaticEngineCG::generate_dynamic_sample_spec_if_need(ObLogExchange &op, ObPxCoordSpec &spec)
{
int ret = OB_SUCCESS;
if (op.get_sort_keys().count() > 0) {
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_sort_keys().count(); ++i) {
if (OB_FAIL(mark_expr_self_produced(op.get_sort_keys().at(i).expr_))) {
LOG_WARN("mark self produced expr failed", K(ret), K(i));
}
}
if (OB_SUCC(ret)) {
ObArray<OrderItem> sort_keys;
if (OB_FAIL(filter_sort_keys(op, op.get_sort_keys(), sort_keys))) {
LOG_WARN("filter out expr of partition id failed", K(ret));
} else if (OB_FAIL(spec.sort_exprs_.init(sort_keys.count()))) {
LOG_WARN("failed to init dynamic sample exprs", K(ret));
} else if (OB_FAIL(fill_sort_info(sort_keys, spec.sort_collations_, spec.sort_exprs_))) {
LOG_WARN("failed to fill sort info", K(ret));
} else if (OB_FAIL(fill_sort_funcs(spec.sort_collations_, spec.sort_cmp_funs_, spec.sort_exprs_))) {
LOG_WARN("failed to fill sort funcs", K(ret));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxFifoCoordSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_receive_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic transmit spec", K(ret));
} else if (OB_FAIL(generate_dynamic_sample_spec_if_need(op, spec))) {
LOG_WARN("generate px_coord_spec for dynamic sample failed", K(ret));
} else {
if (op.get_plan()->get_optimizer_context().is_online_ddl()) {
LOG_INFO("ddl plan", K(*op.get_plan()));
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogExchange &op, ObPxOrderedCoordSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_basic_receive_spec(op, spec, in_root_job))) {
LOG_WARN("failed to generate basic transmit spec", K(ret));
} else if (OB_FAIL(generate_dynamic_sample_spec_if_need(op, spec))) {
LOG_WARN("generate px_coord_spec for dynamic sample failed", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTempTableAccess &op, ObTempTableAccessOpSpec &spec, const bool)
{
int ret = OB_SUCCESS;
ObIArray<ObRawExpr*> &access_exprs = op.get_access_exprs();
bool is_distributed = false;
if (OB_FAIL(spec.init_output_index(access_exprs.count()))) {
LOG_WARN("failed to init output index.", K(ret));
} else if (OB_FAIL(spec.init_access_exprs(access_exprs.count()))) {
LOG_WARN("failed to init access exprs.", K(ret));
} else if (OB_FAIL(get_is_distributed(op, is_distributed))) {
LOG_WARN("failed get is distributed.", K(ret));
} else {
phy_plan_->set_use_temp_table(true);
spec.set_distributed(is_distributed);
spec.set_temp_table_id(op.get_temp_table_id());
ARRAY_FOREACH(access_exprs, i) {
if (OB_ISNULL(access_exprs.at(i)) || !access_exprs.at(i)->is_column_ref_expr()) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("expected basic column expr", K(ret));
} else {
ObColumnRefRawExpr* col_expr = static_cast<ObColumnRefRawExpr *>(access_exprs.at(i));
int64_t index = col_expr->get_column_id() - OB_APP_MIN_COLUMN_ID;
ObExpr *expr = NULL;
if (OB_FAIL(spec.add_output_index(index))) {
LOG_WARN("failed to add output index", K(ret), K(index));
} else if (OB_FAIL(generate_rt_expr(*access_exprs.at(i), expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (OB_FAIL(spec.add_access_expr(expr))) {
LOG_WARN("failed to add output index", K(ret), K(*col_expr));
} else if (OB_FAIL(mark_expr_self_produced(col_expr))) { // temp table access need to set IS_COLUMNLIZED flag
LOG_WARN("mark expr self produced failed", K(ret));
} else { /*do nothing.*/ }
}
} // end for
}
return ret;
}
int ObStaticEngineCG::get_is_distributed(ObLogTempTableAccess &op, bool &is_distributed)
{
int ret = OB_SUCCESS;
is_distributed = false;
ObLogicalOperator *parent = NULL;
ObLogPlan *log_plan = op.get_plan();
const uint64_t temp_table_id = op.get_temp_table_id();
if (OB_ISNULL(log_plan)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected null", K(ret));
} else {
ObIArray<ObSqlTempTableInfo*> &temp_tables = log_plan->get_optimizer_context().get_temp_table_infos();
bool find = false;
for (int64_t i = 0; OB_SUCC(ret) && !find && i < temp_tables.count(); ++i) {
if (OB_ISNULL(temp_tables.at(i)) || OB_ISNULL(temp_tables.at(i)->table_plan_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected null", K(ret));
} else if (temp_table_id != temp_tables.at(i)->temp_table_id_) {
/* do nothing */
} else if (OB_ISNULL(parent = temp_tables.at(i)->table_plan_->get_parent())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret));
} else {
find = true;
while (OB_NOT_NULL(parent)) {
if (log_op_def::LOG_EXCHANGE == parent->get_type()) {
is_distributed = true;
break;
} else if (log_op_def::LOG_TEMP_TABLE_TRANSFORMATION == parent->get_type()) {
break;
} else {
parent = parent->get_parent();
}
}
}
}
if (OB_SUCC(ret) && !find) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("failed to find table plan", K(ret), K(op));
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTempTableInsert &op, ObTempTableInsertOpSpec &spec, const bool)
{
int ret = OB_SUCCESS;
ObLogicalOperator *parent = NULL;
bool is_distributed = false;
if (OB_ISNULL(parent = op.get_parent())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret));
} else if (log_op_def::LOG_EXCHANGE == parent->get_type()) {
is_distributed = true;
}
spec.set_distributed(is_distributed);
spec.set_temp_table_id(op.get_temp_table_id());
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTempTableTransformation &op, ObTempTableTransformationOpSpec &spec, const bool)
{
int ret = OB_SUCCESS;
UNUSED(spec);
ObSEArray<ObExpr*, 4> output_exprs;
if (OB_FAIL(generate_rt_exprs(op.get_output_exprs(), output_exprs))) {
LOG_WARN("failed to generate rt exprs", K(ret));
} else { /*do nothing.*/ }
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTableScan &op, ObTableScanSpec &spec, const bool)
{
int ret = OB_SUCCESS;
// generate_spec() interface is override heavy, check type here to avoid generate subclass
// of ObTableScanSpec unintentionally.
// e.g.: forget override generate_spec() for subclass of ObTableScanSpec.
CK(typeid(spec) == typeid(ObTableScanSpec));
OZ(generate_normal_tsc(op, spec));
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTableScan &op, ObFakeCTETableSpec &spec, const bool)
{
int ret = OB_SUCCESS;
OZ(generate_cte_table_spec(op, spec));
return ret;
}
int ObStaticEngineCG::generate_cte_table_spec(ObLogTableScan &op, ObFakeCTETableSpec &spec)
{
int ret = OB_SUCCESS;
if (OB_FAIL(fake_cte_tables_.push_back(spec.get_id()))) {
LOG_WARN("fake cte table push back failed", K(ret));
} else {
const ObIArray<ObRawExpr*> &access_exprs = op.get_access_exprs();
LOG_DEBUG("Table scan's access columns", K(access_exprs.count()));
OZ(spec.column_involved_offset_.init(access_exprs.count()));
OZ(spec.column_involved_exprs_.init(access_exprs.count()));
ARRAY_FOREACH(access_exprs, i) {
ObRawExpr* expr = access_exprs.at(i);
ObExpr *rt_expr = nullptr;
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(expr));
} else if (expr->has_flag(IS_CONST)) {
} else if (OB_UNLIKELY(!expr->is_column_ref_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expected basic column", K(ret));
} else if (OB_FAIL(generate_rt_expr(*expr, rt_expr))) {
LOG_WARN("Fail to generate rt expr", KPC(expr), K(rt_expr));
} else if (OB_ISNULL(rt_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("rt expr is null", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(expr))) { // access_exprs in convert_cte_pump need to set IS_COLUMNLIZED flag
LOG_WARN("mark expr self produced failed", K(ret));
} else {
ObColumnRefRawExpr *col_expr = static_cast<ObColumnRefRawExpr *>(expr);
int64_t column_offset = col_expr->get_cte_generate_column_projector_offset();
if (OB_FAIL(spec.column_involved_offset_.push_back(column_offset))) {
LOG_WARN("Failed to add column offset", K(ret));
} else if (OB_FAIL(spec.column_involved_exprs_.push_back(rt_expr))) {
LOG_WARN("Fail to add column expr", K(ret));
}
}
} // end for
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogUnpivot &op, ObUnpivotSpec &spec, const bool in_root_job)
{
UNUSED(in_root_job);
int ret = OB_SUCCESS;
CK(typeid(spec) == typeid(ObUnpivotSpec));
OX(spec.unpivot_info_ = op.unpivot_info_);
ObOpSpec *child = spec.get_child(0);
if (OB_SUCC(ret)) {
if (OB_ISNULL(child)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("no child", K(ret));
} else if (!spec.unpivot_info_.has_unpivot()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unpivot_info_ is invalid", K(ret));
} else {
CK(0 != spec.unpivot_info_.get_new_column_count());
spec.max_part_count_ = (child->get_output_count() - spec.unpivot_info_.old_column_count_)
/ spec.unpivot_info_.get_new_column_count();
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogGroupBy &op, ObScalarAggregateSpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
int ret = OB_SUCCESS;
if (OB_UNLIKELY(op.get_num_of_child() != 1 || OB_ISNULL(op.get_child(0)))) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("wrong number of children", K(ret), K(op.get_num_of_child()));
} else if (OB_FAIL(fill_aggr_infos(op, spec))) {
OB_LOG(WARN, "fail to fill_aggr_infos", K(ret));
} else if (nullptr != op.get_aggr_code_expr()
&& OB_FAIL(generate_rt_expr(*op.get_aggr_code_expr(), spec.aggr_code_expr_))) {
LOG_WARN("failed to generate aggr code expr", K(ret));
} else if (OB_FAIL(generate_dist_aggr_group(op, spec))) {
LOG_WARN("failed to generate distinct aggregate function duplicate columns", K(ret));
} else {
spec.by_pass_enabled_ = false;
OZ(set_3stage_info(op, spec));
}
LOG_DEBUG("finish generate_spec", K(spec), K(ret));
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogGroupBy &op, ObMergeGroupBySpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
int ret = OB_SUCCESS;
if (OB_UNLIKELY(op.get_num_of_child() != 1 || OB_ISNULL(op.get_child(0)))) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("wrong number of children", K(ret), K(op.get_num_of_child()));
} else {
spec.set_rollup(op.has_rollup());
spec.by_pass_enabled_ = false;
OZ(set_3stage_info(op, spec));
OZ(set_rollup_adaptive_info(op, spec));
if (OB_FAIL(ret)) {
} else if (OB_FAIL(generate_dist_aggr_group(op, spec))) {
LOG_WARN("failed to generate distinct aggregate function duplicate columns", K(ret));
} else if (OB_FAIL(spec.distinct_exprs_.init(op.get_distinct_exprs().count()))){
LOG_WARN("failed to init distinct column indexes", K(ret));
} else if (OB_FAIL(generate_rt_exprs(op.get_distinct_exprs(), spec.distinct_exprs_))) {
LOG_WARN("failed to generate distinct column", K(ret));
} else if (nullptr != op.get_aggr_code_expr()
&& OB_FAIL(generate_rt_expr(*op.get_aggr_code_expr(), spec.aggr_code_expr_))) {
LOG_WARN("failed to generate aggr code expr", K(ret));
}
}
// 1. add group columns
if (OB_SUCC(ret)) {
common::ObIArray<ObRawExpr*> &group_exprs = op.get_group_by_exprs();
if (OB_FAIL(spec.init_group_exprs(group_exprs.count()))) {
OB_LOG(WARN, "fail to init group expr", K(ret));
}
ARRAY_FOREACH(group_exprs, i) {
const ObRawExpr *raw_expr = group_exprs.at(i);
ObExpr *expr = NULL;
if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_FAIL(spec.add_group_expr(expr))) {
OB_LOG(WARN, "fail to add_group_expr", K(ret));
}
} // end for
}
// 2. add rollup columns
if (OB_SUCC(ret)) {
common::ObIArray<ObRawExpr*> &rollup_exprs = op.get_rollup_exprs();
if (OB_FAIL(spec.init_rollup_exprs(rollup_exprs.count()))) {
OB_LOG(WARN, "fail to init rollup expr", K(ret));
} else if (OB_FAIL(spec.init_duplicate_rollup_expr(rollup_exprs.count()))) {
OB_LOG(WARN, "fail to init_duplicate_rollup_expr", K(ret));
}
bool is_duplicate = false;
ARRAY_FOREACH(rollup_exprs, i) {
const ObRawExpr* raw_expr = rollup_exprs.at(i);
ObExpr *expr = NULL;
if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (FALSE_IT(is_duplicate = (has_exist_in_array(spec.group_exprs_, expr)
|| has_exist_in_array(spec.rollup_exprs_, expr)))) {
} else if (OB_FAIL(spec.is_duplicate_rollup_expr_.push_back(is_duplicate))) {
OB_LOG(WARN, "fail to push distinct_rollup_expr", K(ret));
} else if (OB_FAIL(spec.add_rollup_expr(expr))) {
OB_LOG(WARN, "fail to add_rollup_expr", K(ret));
} else {
LOG_DEBUG("rollup is duplicate key", K(is_duplicate));
}
} // end for
}
// 3. add aggr columns
if (OB_SUCC(ret)) {
// first stage should not use merge-groupby
// TODO: need judge distinct_exprs should to be implicit aggr expr
if (OB_FAIL(fill_aggr_infos(op, spec, &spec.group_exprs_, &spec.rollup_exprs_, nullptr))) {
OB_LOG(WARN, "fail to fill_aggr_infos", K(ret));
}
}
LOG_DEBUG("succ to generate_spec", K(spec), K(ret));
return ret;
}
int ObStaticEngineCG::set_3stage_info(ObLogGroupBy &op, ObGroupBySpec &spec)
{
int ret = OB_SUCCESS;
spec.aggr_stage_ = op.get_aggr_stage();
spec.aggr_code_idx_ = op.get_aggr_code_idx();
return ret;
}
int ObStaticEngineCG::set_rollup_adaptive_info(ObLogGroupBy &op, ObMergeGroupBySpec &spec)
{
int ret = OB_SUCCESS;
spec.rollup_status_ = op.get_rollup_status();
spec.is_parallel_ = ObRollupStatus::ROLLUP_DISTRIBUTOR == spec.rollup_status_ ? true : false;
if (nullptr != op.get_rollup_id_expr()) {
OZ(generate_rt_expr(*op.get_rollup_id_expr(), spec.rollup_id_expr_));
}
if (OB_SUCC(ret) && 0 < op.get_inner_sort_keys().count()) {
ObIArray<OrderItem> &sork_keys = op.get_inner_sort_keys();
if (OB_FAIL(spec.sort_exprs_.init(sork_keys.count()))) {
LOG_WARN("failed to init all exprs", K(ret));
} else if (OB_FAIL(fill_sort_info(sork_keys, spec.sort_collations_, spec.sort_exprs_))) {
LOG_WARN("failed to sort info", K(ret));
} else if (OB_FAIL(fill_sort_funcs(
spec.sort_collations_, spec.sort_cmp_funcs_, spec.sort_exprs_))) {
LOG_WARN("failed to sort funcs", K(ret));
} else {
spec.enable_encode_sort_ = op.has_encode_sort();
LOG_TRACE("debug enable encode sort", K(op.has_encode_sort()));
}
}
return ret;
}
int ObStaticEngineCG::generate_dist_aggr_group(ObLogGroupBy &op, ObGroupBySpec &spec)
{
int ret = OB_SUCCESS;
if (OB_SUCC(ret) && OB_FAIL(spec.dist_aggr_group_idxes_.init(op.get_distinct_aggr_batch().count()))) {
LOG_WARN("failed to init array", K(ret));
}
int64_t aggr_group_idx = 0;
for (int64_t i = 0; i < op.get_distinct_aggr_batch().count() && OB_SUCC(ret); ++i) {
const ObDistinctAggrBatch &distinct_batch = op.get_distinct_aggr_batch().at(i);
aggr_group_idx += distinct_batch.mocked_aggrs_.count();
if (OB_FAIL(spec.dist_aggr_group_idxes_.push_back(aggr_group_idx))) {
LOG_WARN("failed to push back aggr group aggr inndex", K(ret));
}
} // end for
return ret;
}
int ObStaticEngineCG::generate_dist_aggr_distinct_columns(
ObLogGroupBy &op, ObHashGroupBySpec &spec)
{
int ret = OB_SUCCESS;
if (op.is_three_stage_aggr()) {
// duplicate column start with aggr_code
int64_t dist_col_group_idx = 0;
for (int64_t i = 0; i < op.get_distinct_aggr_batch().count() && OB_SUCC(ret); ++i) {
const ObDistinctAggrBatch &distinct_batch = op.get_distinct_aggr_batch().at(i);
dist_col_group_idx += distinct_batch.mocked_params_.count();
LOG_DEBUG("debug distinct columns", K(i), K(distinct_batch.mocked_params_.count()),
K(dist_col_group_idx));
}
if (OB_SUCC(ret)) {
if (OB_FAIL(spec.dist_col_group_idxs_.init(dist_col_group_idx))) {
LOG_WARN("failed to init array", K(ret));
} else if (OB_FAIL(spec.org_dup_cols_.init(dist_col_group_idx))) {
LOG_WARN("failed to push back org_expr", K(ret));
} else if (OB_FAIL(spec.new_dup_cols_.init(dist_col_group_idx))) {
LOG_WARN("failed to push back org_expr", K(ret));
}
}
LOG_DEBUG("debug generate distinct aggr duplicate info", K(ret), K(dist_col_group_idx),
K(op.get_distinct_aggr_batch().count()));
dist_col_group_idx = op.get_aggr_code_idx() + 1;
for (int64_t i = 0; i < op.get_distinct_aggr_batch().count() && OB_SUCC(ret); ++i) {
const ObDistinctAggrBatch &distinct_batch = op.get_distinct_aggr_batch().at(i);
ObExpr *org_expr = nullptr;
ObExpr *dup_expr = nullptr;
dist_col_group_idx += distinct_batch.mocked_params_.count();
if (OB_FAIL(spec.dist_col_group_idxs_.push_back(dist_col_group_idx))) {
LOG_WARN("failed to push back aggr group aggr inndex", K(ret));
}
for (int64_t j = 0; op.is_first_stage() && j < distinct_batch.mocked_params_.count() && OB_SUCC(ret); ++j) {
const std::pair<ObRawExpr *, ObRawExpr *> &pair = distinct_batch.mocked_params_.at(j);
if (OB_FAIL(generate_rt_expr(*pair.first, org_expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_FAIL(generate_rt_expr(*pair.second, dup_expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_FAIL(spec.org_dup_cols_.push_back(org_expr))) {
LOG_WARN("failed to push back org_expr", K(ret));
} else if (OB_FAIL(spec.new_dup_cols_.push_back(dup_expr))) {
LOG_WARN("failed to push back org_expr", K(ret));
}
} // end inner for
} // end outer for
// it's second or third stage
if (OB_FAIL(ret)) {
} else if (OB_FAIL(generate_dist_aggr_group(op, spec))) {
LOG_WARN("failed to generate dist aggr group", K(ret), K(spec.id_));
} else if (0 == spec.dist_col_group_idxs_.count() ||
spec.dist_col_group_idxs_.count() != spec.dist_aggr_group_idxes_.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: distinct columns group is not match distinct aggregate function",
K(ret), K(spec.id_),
K(spec.dist_aggr_group_idxes_.count()),
K(spec.dist_col_group_idxs_.count()));
} else if (op.is_first_stage()) {
spec.dist_aggr_group_idxes_.reset();
} else {
spec.dist_col_group_idxs_.reset();
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogGroupBy &op, ObHashGroupBySpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
int ret = OB_SUCCESS;
if (OB_UNLIKELY(op.get_num_of_child() != 1 || OB_ISNULL(op.get_child(0)))) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("wrong number of children", K(ret), K(op.get_num_of_child()));
} else {
spec.set_est_group_cnt(op.get_distinct_card());
OZ(set_3stage_info(op, spec));
spec.by_pass_enabled_ = op.is_adaptive_aggregate();
if (OB_FAIL(ret)) {
} else if (OB_FAIL(generate_dist_aggr_distinct_columns(op, spec))) {
LOG_WARN("failed to generate distinct aggregate function duplicate columns", K(ret));
} else if (OB_FAIL(spec.distinct_exprs_.init(op.get_distinct_exprs().count()))){
LOG_WARN("failed to init distinct column indexes", K(ret));
} else if (OB_FAIL(generate_rt_exprs(op.get_distinct_exprs(), spec.distinct_exprs_))) {
LOG_WARN("failed to generate distinct column", K(ret));
} else if (nullptr != op.get_aggr_code_expr()
&& OB_FAIL(generate_rt_expr(*op.get_aggr_code_expr(), spec.aggr_code_expr_))) {
LOG_WARN("failed to generate aggr code expr", K(ret));
}
}
// 1. add group columns
if (OB_SUCC(ret)) {
common::ObIArray<ObRawExpr*> &group_exprs = op.get_group_by_exprs();
if (OB_FAIL(spec.init_group_exprs(group_exprs.count()))) {
OB_LOG(WARN, "fail to init group expr", K(ret));
} else if (OB_FAIL(spec.cmp_funcs_.init(group_exprs.count()))) {
OB_LOG(WARN, "fail to init group expr", K(ret));
}
ARRAY_FOREACH(group_exprs, i) {
const ObRawExpr *raw_expr = group_exprs.at(i);
ObExpr *expr = NULL;
if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_FAIL(spec.add_group_expr(expr))) {
OB_LOG(WARN, "fail to add_group_expr", K(ret));
} else {
ObCmpFunc cmp_func;
// no matter null first or null last.
cmp_func.cmp_func_ = expr->basic_funcs_->null_last_cmp_;
CK(NULL != cmp_func.cmp_func_);
OZ(spec.cmp_funcs_.push_back(cmp_func));
}
} // end for
}
// 2. add aggr columns
if (OB_SUCC(ret)) {
// TODO: need judge distinct_exprs should to be implicit aggr expr
if (OB_FAIL(fill_aggr_infos(op, spec, &spec.group_exprs_, nullptr, nullptr))) {
OB_LOG(WARN, "fail to fill_aggr_infos", K(ret));
}
}
LOG_DEBUG("succ to generate_spec", K(spec), K(ret), K(spec.distinct_exprs_));
return ret;
}
// copy from ObCodeGeneratorImpl::convert_normal_table_scan
int ObStaticEngineCG::generate_normal_tsc(ObLogTableScan &op, ObTableScanSpec &spec)
{
ObString tbl_name;
ObString index_name;
int ret = OB_SUCCESS;
ObSqlSchemaGuard *schema_guard = OB_ISNULL(op.get_plan())
? NULL
: op.get_plan()->get_optimizer_context().get_sql_schema_guard();
CK(OB_NOT_NULL(schema_guard));
if (OB_SUCC(ret) && NULL != op.get_pre_query_range()) {
OZ(spec.tsc_ctdef_.pre_query_range_.deep_copy(*op.get_pre_query_range()));
op.get_pre_query_range()->is_get(spec.tsc_ctdef_.scan_ctdef_.is_get_);
}
bool is_equal_and = true;
ObKeyPart* root = spec.tsc_ctdef_.pre_query_range_.get_table_grapth().key_part_head_;
ObSEArray<ObQueryRange::ObEqualOff, 1> equal_offs;
while (OB_SUCC(ret) && NULL != root && is_equal_and) {
is_equal_and = is_equal_and & root->is_equal_condition();
if (NULL != root->item_next_ || NULL != root->or_next_) {
is_equal_and = false;
} else if (NULL != root->normal_keypart_) {
int64_t param_idx = OB_INVALID_ID;
ObObj& cur = root->normal_keypart_->start_;
ObQueryRange::ObEqualOff equal_off;
if (cur.is_ext() || root->null_safe_) {
is_equal_and = false; //roolback old version
} else if (root->is_rowid_key_part()) {
is_equal_and = false; //not deal with rowid
} else if (cur.is_unknown()) {
if (OB_FAIL(cur.get_unknown(param_idx))) {
LOG_WARN("get question mark value failed", K(ret), K(cur));
} else {
equal_off.param_idx_ = param_idx;
equal_off.pos_off_ = root->pos_.offset_;
equal_off.pos_type_ = root->pos_.column_type_.get_type();
equal_offs.push_back(equal_off);
}
} else {
equal_off.only_pos_ = true;
equal_off.pos_off_ = root->pos_.offset_;
equal_off.pos_value_ = root->normal_keypart_->start_;
equal_offs.push_back(equal_off);
}
}
root = root->and_next_;
}
spec.tsc_ctdef_.pre_query_range_.set_is_equal_and(is_equal_and);
spec.tsc_ctdef_.pre_query_range_.get_equal_offs().assign(equal_offs);
OZ(ob_write_string(phy_plan_->get_allocator(), op.get_table_name(), tbl_name));
OZ(ob_write_string(phy_plan_->get_allocator(), op.get_index_name(), index_name));
bool is_top_table_scan = false;
OZ(op.is_top_table_scan(is_top_table_scan));
spec.is_top_table_scan_ = is_top_table_scan;
OZ(set_optimization_info(op, spec));
OZ(set_partition_range_info(op, spec));
if (OB_SUCC(ret)) {
spec.table_loc_id_ = op.get_table_id();
spec.ref_table_id_ = op.get_ref_table_id();
spec.is_index_global_ = op.get_is_index_global();
spec.frozen_version_ = op.get_plan()->get_optimizer_context().get_global_hint().frozen_version_;
spec.force_refresh_lc_ = op.get_plan()->get_optimizer_context().get_global_hint().force_refresh_lc_;
spec.use_dist_das_ = op.use_das();
spec.batch_scan_flag_ = op.use_batch();
spec.table_row_count_ = op.get_table_row_count();
spec.output_row_count_ = static_cast<int64_t>(op.get_output_row_count());
spec.query_range_row_count_ = static_cast<int64_t>(op.get_query_range_row_count());
spec.index_back_row_count_ = static_cast<int64_t>(op.get_index_back_row_count());
spec.estimate_method_ = op.get_estimate_method();
spec.table_name_ = tbl_name;
spec.index_name_ = index_name;
// das path not under gi control (TODO: separate gi_above flag from das tsc spec)
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
if (op.is_table_whole_range_scan()) {
phy_plan_->set_contain_table_scan(true);
}
if (OB_NOT_NULL(op.get_table_partition_info())) {
op.get_table_partition_info()->get_table_location().set_use_das(spec.use_dist_das_);
}
if (NULL != op.get_limit_expr()) {
CK(op.get_limit_expr()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_limit_expr(), spec.limit_));
}
if (OB_SUCC(ret) && NULL != op.get_offset_expr()) {
CK(op.get_offset_expr()->get_result_type().is_integer_type());
OZ(generate_rt_expr(*op.get_offset_expr(), spec.offset_));
}
}
if (OB_SUCC(ret)) {
if (opt_ctx_->is_online_ddl() && stmt::T_INSERT == opt_ctx_->get_session_info()->get_stmt_type()) {
spec.report_col_checksum_ = true;
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(tsc_cg_service_.generate_tsc_ctdef(op, spec.tsc_ctdef_))) {
LOG_WARN("generate tsc ctdef failed", K(ret));
} else if (is_oracle_mapping_real_virtual_table(op.get_ref_table_id())) {
if (OB_FAIL(tsc_cg_service_.generate_agent_vt_access_meta(op, spec))) {
LOG_WARN("generate virtual agent table access meta failed", K(ret));
}
}
LOG_TRACE("CG index table scan",
K(spec.tsc_ctdef_.scan_ctdef_.ref_table_id_),
K(spec.table_loc_id_),
K(spec.ref_table_id_),
K(op.get_ref_table_id()),
K(op.get_index_table_id()),
K(tbl_name), K(index_name));
}
if (OB_SUCC(ret)) {
if (op.is_sample_scan()
&& op.get_sample_info().method_ == SampleInfo::ROW_SAMPLE) {
ObRowSampleScanSpec &sample_scan = static_cast<ObRowSampleScanSpec &>(spec);
sample_scan.set_sample_info(op.get_sample_info());
}
if (OB_SUCC(ret) && op.is_sample_scan()
&& op.get_sample_info().method_ == SampleInfo::BLOCK_SAMPLE) {
ObBlockSampleScanSpec &sample_scan = static_cast<ObBlockSampleScanSpec &>(spec);
sample_scan.set_sample_info(op.get_sample_info());
}
}
if (OB_SUCC(ret) && spec.report_col_checksum_) {
if (OB_FAIL(tsc_cg_service_.generate_ddl_output_column_ids(op, spec))) {
LOG_WARN("generate ddl output column ids failed", K(ret));
}
}
if (OB_SUCC(ret) && 0 != op.get_session_id()) {
//此时一定是临时表扫描, 记下session_id供计划缓存匹配时使用
phy_plan_->set_session_id(op.get_session_id());
}
if (OB_SUCC(ret)) {
bool found = false;
for (int64_t i = 0; i < op.get_output_exprs().count() && !found && OB_SUCC(ret); i++) {
const ObRawExpr *expr = NULL;
ObExpr *rt_expr = NULL;
if (OB_ISNULL(expr = op.get_output_exprs().at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("output expr is null", K(ret));
} else if (expr->get_expr_type() != T_PDML_PARTITION_ID) {
// do nothing
} else if (OB_FAIL(generate_rt_expr(*expr, rt_expr))) {
LOG_WARN("generate rt expr failed", K(ret));
} else {
spec.pdml_partition_id_ = rt_expr;
found = true;
}
}
}
return ret;
}
int ObStaticEngineCG::generate_param_spec(
const common::ObIArray<ObExecParamRawExpr *> &param_raw_exprs,
ObFixedArray<ObDynamicParamSetter, ObIAllocator> &param_setter)
{
int ret = OB_SUCCESS;
ObDynamicParamSetter setter;
OZ(param_setter.init(param_raw_exprs.count()));
for (int64_t k = 0; OB_SUCC(ret) && k < param_raw_exprs.count(); k++) {
ObExecParamRawExpr *exec_param = param_raw_exprs.at(k);
CK (NULL != exec_param);
CK (NULL != exec_param->get_ref_expr());
CK (exec_param->get_param_index() >= 0);
if (OB_SUCC(ret)) {
setter.param_idx_ = exec_param->get_param_index();
}
OZ(generate_rt_expr(*exec_param->get_ref_expr(),
*reinterpret_cast<ObExpr **>(&setter.src_)));
OZ(generate_rt_expr(*exec_param,
*const_cast<ObExpr **>(&setter.dst_)));
OZ(param_setter.push_back(setter));
}
return ret;
}
int ObStaticEngineCG::generate_pseudo_column_expr(
ObLogJoin &op,
ObNLConnectBySpecBase &spec)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_connect_by_pseudo_columns().count(); ++i) {
ObRawExpr *expr = op.get_connect_by_pseudo_columns().at(i);
ObItemType expr_type = expr->get_expr_type();
OZ(mark_expr_self_produced(expr)); // connect by pseudo column exprs need to set IS_COLUMNLIZED flag
switch (expr_type) {
case T_LEVEL:
OZ(generate_rt_expr(*expr, spec.level_expr_));
LOG_DEBUG("generate level expr");
break;
case T_CONNECT_BY_ISLEAF:
OZ(generate_rt_expr(*expr, spec.is_leaf_expr_));
LOG_DEBUG("generate isleaf expr");
break;
case T_CONNECT_BY_ISCYCLE:
OZ(generate_rt_expr(*expr, spec.is_cycle_expr_));
LOG_DEBUG("generate iscycle expr");
break;
default:
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid expr", KPC(expr), K(ret));
}
}
return ret;
}
int ObStaticEngineCG::need_prior_exprs(
ObIArray<ObExpr*> &self_output,
ObIArray<ObExpr*> &left_output,
bool &need_prior)
{
int ret = OB_SUCCESS;
need_prior = false;
for (int64_t i = 0; !need_prior && i < left_output.count(); ++i) {
ObExpr *expr = left_output.at(i);
if (is_contain(self_output, expr)) {
need_prior = true;
}
}
return ret;
}
// left exprs + right exprs
// connect by pump:
// pump_row :[left|right row], it need same count from left and right
// output_row: [prior exprs + siblings exprs + pseudo exprs]
// 简单讲就是left和right写入pump的数据是一致的,即依赖的列都需要写入
int ObStaticEngineCG::generate_pump_exprs(ObLogJoin &op, ObNLConnectBySpecBase &spec)
{
int ret = OB_SUCCESS;
ObSEArray<ObExpr*, 8> self_output;
ObLogicalOperator *left_op = op.get_child(0);
ObLogicalOperator *right_op = op.get_child(1);
ObIArray<ObRawExpr *> &left_output = left_op->get_output_exprs();
ObIArray<ObRawExpr *> &right_output = right_op->get_output_exprs();
const ObSelectStmt *select_stmt = static_cast<const ObSelectStmt *>(op.get_stmt());
spec.is_nocycle_ = select_stmt->is_nocycle();
spec.has_prior_ = select_stmt->has_prior();
if (OB_ISNULL(left_op) || OB_ISNULL(right_op)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: child is null", K(ret));
} else if (OB_FAIL(generate_pseudo_column_expr(op, spec))) {
LOG_WARN("failed to generate pseudo column", K(ret));
} else if (OB_FAIL(spec.connect_by_prior_exprs_.init(left_output.count()))) {
LOG_WARN("failed to init left pump exprs", K(ret));
} else if (OB_FAIL(generate_rt_exprs(
op.get_connect_by_prior_exprs(), spec.connect_by_prior_exprs_))) {
LOG_WARN("failed to generate prior exprs", K(ret));
} else if (OB_FAIL(spec.left_prior_exprs_.init(left_output.count()))) {
LOG_WARN("failed to init left pump exprs", K(ret));
} else if (OB_FAIL(spec.right_prior_exprs_.init(right_output.count()))) {
LOG_WARN("failed to init left pump exprs", K(ret));
} else {
ObExpr *left_expr = nullptr;
ObExpr *right_expr = nullptr;
for (int64_t i = 0; i < left_output.count() && OB_SUCC(ret); ++i) {
ObRawExpr *left_raw_expr = left_output.at(i);
ObRawExpr *right_raw_expr = NULL;
if (OB_ISNULL(left_raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(get_connect_by_copy_expr(*left_raw_expr, right_raw_expr, right_output))) {
LOG_WARN("failed to get connect by copy expr", K(ret));
} else if (OB_ISNULL(right_raw_expr)) {
// do nothing
} else if (OB_FAIL(generate_rt_expr(*left_raw_expr, left_expr))) {
LOG_WARN("failed to generate left rt expr", K(ret));
} else if (OB_FAIL(generate_rt_expr(*right_raw_expr, right_expr))) {
LOG_WARN("failed to generate right rt expr", K(ret));
} else if (OB_FAIL(spec.left_prior_exprs_.push_back(left_expr))) {
LOG_WARN("failed to push back left expr", K(ret));
} else if (OB_FAIL(spec.right_prior_exprs_.push_back(right_expr))) {
LOG_WARN("failed to push back left expr", K(ret));
}
}
if (OB_SUCC(ret)) {
LOG_DEBUG("prior info", K(select_stmt->has_prior()), K(spec.connect_by_prior_exprs_),
K(op.get_connect_by_prior_exprs()));
bool need_prior = false;
int64_t left_prior_cnt = 1 + select_stmt->get_order_item_size();
if (OB_FAIL(generate_rt_exprs(op.get_output_exprs(), self_output))) {
LOG_WARN("failed to generate rt exprs", K(ret));
} else if (OB_FAIL(need_prior_exprs(self_output, spec.left_prior_exprs_, need_prior))) {
LOG_WARN("failed to calc prior exprs needed", K(ret));
} else if (FALSE_IT(need_prior = (need_prior
|| select_stmt->has_prior()
|| spec.connect_by_prior_exprs_.count()))) {
} else if (OB_FAIL(spec.cur_row_exprs_.init(
need_prior ? spec.left_prior_exprs_.count() + left_prior_cnt : left_prior_cnt))) {
LOG_WARN("failed to init cur row exprs", K(ret));
} else if (need_prior && OB_FAIL(append(spec.cur_row_exprs_, spec.left_prior_exprs_))) {
LOG_WARN("failed to push back prior exprs", K(ret));
} else if (nullptr != spec.level_expr_ && PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX == spec.type_
&& OB_FAIL(spec.cur_row_exprs_.push_back(spec.level_expr_))) {
LOG_WARN("failed to push back prior exprs", K(ret));
}
}
if (OB_SUCC(ret)) {
ObExpr *expr = nullptr;
ObSEArray<ObRawExpr *, 8> connect_by_root_exprs;
OZ(select_stmt->get_connect_by_root_exprs(connect_by_root_exprs));
OZ(spec.connect_by_root_exprs_.init(connect_by_root_exprs.count()));
for (int64_t i = 0; OB_SUCC(ret) && i < connect_by_root_exprs.count(); ++i) {
ObRawExpr *root_expr = connect_by_root_exprs.at(i);
if (OB_FAIL(generate_rt_expr(*root_expr, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (OB_FAIL(spec.connect_by_root_exprs_.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
}
if (OB_SUCC(ret)) {
ObExpr *expr = nullptr;
ObSEArray<ObRawExpr *, 8> sys_connect_by_path_exprs;
OZ(select_stmt->get_sys_connect_by_path_exprs(sys_connect_by_path_exprs));
OZ(spec.sys_connect_exprs_.init(sys_connect_by_path_exprs.count()));
for (int64_t i = 0; OB_SUCC(ret) && i <sys_connect_by_path_exprs.count(); ++i) {
ObRawExpr *sys_expr = sys_connect_by_path_exprs.at(i);
if (OB_FAIL(generate_rt_expr(*sys_expr, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (OB_FAIL(spec.sys_connect_exprs_.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
}
if (OB_SUCC(ret)) {
OZ(spec.cmp_funcs_.init(spec.connect_by_prior_exprs_.count()));
for (int64_t i = 0; i < spec.connect_by_prior_exprs_.count() && OB_SUCC(ret); ++i) {
ObExpr *expr = spec.connect_by_prior_exprs_.at(i);
ObCmpFunc cmp_func;
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(
expr->datum_meta_.type_,
expr->datum_meta_.type_,
NULL_LAST,//这里null last还是first无所谓
expr->datum_meta_.cs_type_,
lib::is_oracle_mode());
if (OB_ISNULL(cmp_func.cmp_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp_func is null, check datatype is valid", K(ret));
} else if (OB_FAIL(spec.cmp_funcs_.push_back(cmp_func))) {
LOG_WARN("failed to push back sort function", K(ret));
}
}
}
}
return ret;
}
int ObStaticEngineCG::get_connect_by_copy_expr(ObRawExpr &left_expr,
ObRawExpr *&right_expr,
ObIArray<ObRawExpr *> &right_exprs)
{
int ret = OB_SUCCESS;
right_expr = NULL;
if (OB_LIKELY(left_expr.is_column_ref_expr())) {
const uint64_t column_id = static_cast<ObColumnRefRawExpr &>(left_expr).get_column_id();
for (int64_t i = 0; OB_SUCC(ret) && NULL == right_expr && i < right_exprs.count(); ++i) {
ObRawExpr *cur_expr = right_exprs.at(i);
if (OB_ISNULL(cur_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (!cur_expr->is_column_ref_expr()) {
// do nothing
} else if (column_id == static_cast<ObColumnRefRawExpr *>(cur_expr)->get_column_id()) {
right_expr = cur_expr;
}
}
}
return ret;
}
int ObStaticEngineCG::construct_hash_elements_for_connect_by(ObLogJoin &op, ObNLConnectBySpec &spec)
{
int ret = OB_SUCCESS;
ObLogicalOperator *left_op = NULL;
ObLogicalOperator *right_op = NULL;
ObLogPlan *log_plan = NULL;
ObSQLSessionInfo *session_info = NULL;
if (OB_ISNULL(log_plan = op.get_plan())
|| OB_ISNULL(session_info = log_plan->get_optimizer_context().get_session_info())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("session is null", K(ret), K(log_plan));
} else if (OB_ISNULL(left_op = op.get_child(0)) || OB_ISNULL(right_op = op.get_child(1))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("child op is null", K(ret));
} else {
const ObRelIds &left_table_set = left_op->get_table_set();
const ObRelIds &right_table_set = right_op->get_table_set();
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_other_join_conditions().count(); i++) {
ObRawExpr *other_cond = op.get_other_join_conditions().at(i);
if (OB_ISNULL(other_cond)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("other condition is null", K(ret));
} else if (T_OP_EQ == other_cond->get_expr_type()) {
bool prior_at_left = false;
bool can_use_as_key = false;
if (other_cond->get_param_count() != 2) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected param count of equal", K(ret), KPC(other_cond));
} else if (OB_ISNULL(other_cond->get_param_expr(0))
|| OB_ISNULL(other_cond->get_param_expr(1))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("param expr is null", K(ret), KPC(other_cond));
} else {
const ObRelIds &left_rel_ids = other_cond->get_param_expr(0)->get_relation_ids();
const ObRelIds &right_rel_ids = other_cond->get_param_expr(1)->get_relation_ids();
if (left_rel_ids.is_empty() || right_rel_ids.is_empty()) {
} else if (left_rel_ids.is_subset(left_table_set)
&& right_rel_ids.is_subset(right_table_set)) {
can_use_as_key = true;
prior_at_left = true;
} else if (left_rel_ids.is_subset(right_table_set)
&& right_rel_ids.is_subset(left_table_set)) {
can_use_as_key = true;
}
if (can_use_as_key) {
ObExpr *left_param = NULL;
ObExpr *right_param = NULL;
if (OB_FAIL(generate_rt_expr(*other_cond->get_param_expr(0), left_param))) {
LOG_WARN("generate left expr failed", K(ret));
} else if (OB_FAIL(generate_rt_expr(*other_cond->get_param_expr(1), right_param))) {
LOG_WARN("generate right expr failed", K(ret));
} else if (OB_FAIL(spec.hash_key_exprs_.push_back(prior_at_left ? right_param : left_param))) {
LOG_WARN("push back hash key expr failed", K(ret));
} else if (OB_FAIL(spec.hash_probe_exprs_.push_back(prior_at_left ? left_param : right_param))) {
LOG_WARN("push back hash probe expr failed", K(ret));
}
}
}
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogJoin &op, ObNLConnectBySpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
const ObIArray<ObRawExpr*> &other_join_conds = op.get_other_join_conditions();
if (OB_FAIL(generate_param_spec(op.get_nl_params(), spec.rescan_params_))) {
LOG_WARN("failed to generate parameter", K(ret));
} else if (OB_FAIL(generate_pump_exprs(op, spec))) {
LOG_WARN("failed to generate pump exprs", K(ret));
} else if (OB_FAIL(spec.cond_exprs_.init(other_join_conds.count()))) {
LOG_WARN("failed to init join conditions", K(ret));
} else if (OB_FAIL(generate_rt_exprs(other_join_conds, spec.cond_exprs_))) {
LOG_WARN("failed to generate condition rt exprs", K(ret));
} else if (OB_FAIL(construct_hash_elements_for_connect_by(op, spec))) {
LOG_WARN("construct_hash_elements_for_connect_by failed", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogJoin &op, ObNLConnectByWithIndexSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
const ObIArray<ObRawExpr*> &other_join_conds = op.get_other_join_conditions();
if (OB_FAIL(generate_param_spec(op.get_nl_params(), spec.rescan_params_))) {
LOG_WARN("failed to generate parameter", K(ret));
} else if (OB_FAIL(generate_pump_exprs(op, spec))) {
LOG_WARN("failed to generate pump exprs", K(ret));
} else if (OB_FAIL(spec.cond_exprs_.init(other_join_conds.count()))) {
LOG_WARN("failed to init join conditions", K(ret));
} else if (OB_FAIL(generate_rt_exprs(other_join_conds, spec.cond_exprs_))) {
LOG_WARN("failed to generate condition rt exprs", K(ret));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogJoin &op, ObHashJoinSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
CK (nullptr != op.get_join_path());
if (OB_SUCC(ret) && op.get_join_path()->is_naaj_) {
CK (LEFT_ANTI_JOIN == op.get_join_type() || RIGHT_ANTI_JOIN == op.get_join_type());
OX (spec.is_naaj_ = op.get_join_path()->is_naaj_);
OX (spec.is_sna_ = op.get_join_path()->is_sna_);
}
spec.is_shared_ht_ = HASH_JOIN == op.get_join_algo()
&& DIST_BC2HOST_NONE == op.get_join_distributed_method();
OZ (generate_join_spec(op, spec));
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogJoin &op,
ObNestedLoopJoinSpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
return generate_join_spec(op, spec);
}
int ObStaticEngineCG::generate_spec(ObLogJoin &op,
ObMergeJoinSpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
return generate_join_spec(op, spec);
}
int ObStaticEngineCG::generate_join_spec(ObLogJoin &op, ObJoinSpec &spec)
{
int ret = OB_SUCCESS;
bool is_late_mat = (phy_plan_->get_is_late_materialized() || op.is_late_mat());
phy_plan_->set_is_late_materialized(is_late_mat);
// print log if possible
if (OB_NOT_NULL(op.get_stmt())
&& (stmt::T_INSERT == op.get_stmt()->get_stmt_type()
|| stmt::T_UPDATE == op.get_stmt()->get_stmt_type()
|| stmt::T_DELETE == op.get_stmt()->get_stmt_type())
&& true == is_late_mat) {
LOG_WARN("INSERT, UPDATE or DELETE smt should not be marked as late materialized.",
K(op.get_stmt()->get_stmt_type()), K(is_late_mat), K(*op.get_stmt()));
}
if (op.is_partition_wise()) {
phy_plan_->set_is_wise_join(op.is_partition_wise()); // set is_wise_join
}
// 1. add other join conditions
const ObIArray<ObRawExpr*> &other_join_conds = op.get_other_join_conditions();
OZ(spec.other_join_conds_.init(other_join_conds.count()));
ARRAY_FOREACH(other_join_conds, i) {
ObRawExpr *raw_expr = other_join_conds.at(i);
ObExpr *expr = NULL;
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("null pointer", K(ret));
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("fail to generate rt expr", K(ret), K(*raw_expr));
} else if (OB_FAIL(spec.other_join_conds_.push_back(expr))) {
LOG_WARN("failed to add sql expr", K(ret), K(*expr));
} else {
LOG_DEBUG("equijoin condition", K(*raw_expr), K(*expr));
}
} // end for
spec.join_type_ = op.get_join_type();
if (MERGE_JOIN == op.get_join_algo()) {
//A.1. add equaljoin conditions and populate all exprs for left/right child fetcher
ObMergeJoinSpec &mj_spec = static_cast<ObMergeJoinSpec &>(spec);
const ObIArray<ObRawExpr*> &equal_join_conds = op.get_equal_join_conditions();
OZ(mj_spec.equal_cond_infos_.init(equal_join_conds.count()));
if (OB_ISNULL(mj_spec.get_left())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("left is null", K(ret));
} else if (OB_ISNULL(mj_spec.get_right())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("right is null", K(ret));
} else if (OB_FAIL(mj_spec.left_child_fetcher_all_exprs_.init(
mj_spec.get_left()->output_.count() +
equal_join_conds.count()))) {
LOG_WARN("failed to init left fetcher all exprs", K(ret));
} else if (OB_FAIL(mj_spec.right_child_fetcher_all_exprs_.init(
mj_spec.get_right()->output_.count() +
equal_join_conds.count()))) {
LOG_WARN("failed to init right fetcher all exprs", K(ret));
} else if (OB_FAIL(
append_array_no_dup(mj_spec.left_child_fetcher_all_exprs_,
mj_spec.get_left()->output_))) {
LOG_WARN("fail to append array no dup for left child", K(ret), K(op));
} else if (OB_FAIL(
append_array_no_dup(mj_spec.right_child_fetcher_all_exprs_,
mj_spec.get_right()->output_))) {
LOG_WARN("fail to append array no dup for right child", K(ret), K(op));
}
ARRAY_FOREACH(equal_join_conds, i) {
ObMergeJoinSpec::EqualConditionInfo equal_cond_info;
ObRawExpr *raw_expr = equal_join_conds.at(i);
CK(OB_NOT_NULL(raw_expr));
CK(T_OP_EQ == raw_expr->get_expr_type() || T_OP_NSEQ == raw_expr->get_expr_type());
OZ(generate_rt_expr(*raw_expr, equal_cond_info.expr_));
CK(OB_NOT_NULL(equal_cond_info.expr_));
CK(equal_cond_info.expr_->arg_cnt_ == 2)
CK(OB_NOT_NULL(equal_cond_info.expr_->args_));
CK(OB_NOT_NULL(equal_cond_info.expr_->args_[0]));
CK(OB_NOT_NULL(equal_cond_info.expr_->args_[1]));
if (OB_SUCC(ret)){
ObDatumMeta &l = equal_cond_info.expr_->args_[0]->datum_meta_;
ObDatumMeta &r = equal_cond_info.expr_->args_[1]->datum_meta_;
CK(l.cs_type_ == r.cs_type_);
if (OB_SUCC(ret)) {
equal_cond_info.ns_cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(l.type_,
r.type_, default_null_pos(), l.cs_type_, is_oracle_mode());
CK(OB_NOT_NULL(equal_cond_info.ns_cmp_func_));
OZ(calc_equal_cond_opposite(op, *raw_expr, equal_cond_info.is_opposite_));
OZ(mj_spec.equal_cond_infos_.push_back(equal_cond_info));
// when is_opposite_ is true: left child fetcher accept right
// arg(args_[1]) and vice versa
if (OB_SUCC(ret) && OB_FAIL(add_var_to_array_no_dup(mj_spec.left_child_fetcher_all_exprs_,
!equal_cond_info.is_opposite_ ? equal_cond_info.expr_->args_[0]
: equal_cond_info.expr_->args_[1]))) {
OB_LOG(WARN, "fail to add_var_to_array_no_dup", K(ret));
} else if (OB_SUCC(ret) && OB_FAIL(add_var_to_array_no_dup(mj_spec.right_child_fetcher_all_exprs_,
!equal_cond_info.is_opposite_ ? equal_cond_info.expr_->args_[1]
: equal_cond_info.expr_->args_[0]))) {
OB_LOG(WARN, "fail to add_var_to_array_no_dup", K(ret));
}
LOG_DEBUG("equijoin condition", K(*raw_expr), K(equal_cond_info),
K(equal_cond_info.is_opposite_),
KPC(equal_cond_info.expr_->args_[0]),
KPC(equal_cond_info.expr_->args_[1]));
}
}
} // end for
// A.2. add merge directions
if (OB_SUCC(ret)) {
const ObIArray<ObOrderDirection> &merge_directions = op.get_merge_directions();
bool left_unique = false;
if (OB_FAIL(mj_spec.set_merge_directions(merge_directions))) {
LOG_WARN("fail to set merge directions", K(ret));
} else if (OB_FAIL(op.is_left_unique(left_unique))) {
LOG_WARN("fail to check left unique", K(ret), K(op));
} else {
mj_spec.is_left_unique_ = left_unique;
LOG_DEBUG("merge join left unique", K(left_unique));
}
}
} else if (NESTED_LOOP_JOIN == op.get_join_algo()) { // nested loop join
if (0 != op.get_equal_join_conditions().count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("equal join conditions' count should equal 0", K(ret));
} else {
ObBasicNestedLoopJoinSpec &nlj_spec = static_cast<ObBasicNestedLoopJoinSpec &>(spec);
nlj_spec.enable_gi_partition_pruning_ = op.is_enable_gi_partition_pruning();
if (nlj_spec.enable_gi_partition_pruning_ && OB_FAIL(do_gi_partition_pruning(op, nlj_spec))) {
LOG_WARN("fail do gi partition pruning", K(ret));
} else {
OZ(generate_param_spec(op.get_nl_params(), nlj_spec.rescan_params_));
if (OB_SUCC(ret)) {
// 当nlj条件下推做分布式rescan, 开启px batch rescan
ObNestedLoopJoinSpec &nlj = static_cast<ObNestedLoopJoinSpec &>(spec);
if (op.enable_px_batch_rescan()) {
nlj.enable_px_batch_rescan_ = true;
nlj.left_group_size_ = ObNestedLoopJoinOp::PX_RESCAN_BATCH_ROW_COUNT;
} else {
nlj.enable_px_batch_rescan_ = false;
}
}
if (OB_SUCC(ret) && PHY_NESTED_LOOP_JOIN == spec.type_) {
ObNestedLoopJoinSpec &nlj = static_cast<ObNestedLoopJoinSpec &>(spec);
bool use_batch_nlj = op.can_use_batch_nlj();
if (use_batch_nlj) {
nlj.use_group_ = use_batch_nlj;
}
if (nlj.is_vectorized()) {
// populate other cond join info
const ObIArray<ObExpr *> &conds = spec.other_join_conds_;
if (OB_FAIL(nlj.left_expr_ids_in_other_cond_.prepare_allocate(conds.count()))) {
LOG_WARN("Failed to prepare_allocate left_expr_ids_in_other_cond_", K(ret));
} else {
ARRAY_FOREACH(conds, i) {
auto cond = conds.at(i);
ObSEArray<int, 1> left_expr_ids;
for (auto l_output_idx = 0;
OB_SUCC(ret) && l_output_idx < nlj.get_left()->output_.count();
l_output_idx++) {
// check if left child expr appears in other_condtion
bool appears_in_cond = false;
if (OB_FAIL(cond->contain_expr(
nlj.get_left()->output_.at(l_output_idx), appears_in_cond))) {
LOG_WARN("other expr contain calculate failed", K(ret), KPC(cond),
K(l_output_idx),
KPC(nlj.get_left()->output_.at(l_output_idx)));
} else {
if (appears_in_cond) {
if (OB_FAIL(left_expr_ids.push_back(l_output_idx))) {
LOG_WARN("other expr contain", K(ret));
}
}
}
}
// Note: no need to call init explicitly as init() is invoked inside assign()
OZ(nlj.left_expr_ids_in_other_cond_.at(i).assign(left_expr_ids));
}
}
}
}
}
}
} else if (HASH_JOIN == op.get_join_algo()) {
ObSEArray<ObExpr*, 4> right_key_exprs;
ObSEArray<ObHashFunc, 4> right_hash_funcs;
ObHashJoinSpec &hj_spec = static_cast<ObHashJoinSpec&>(spec);
if (OB_ISNULL(hj_spec.get_left()) || OB_ISNULL(hj_spec.get_right())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("children of hj is not init",
K(ret), KP(hj_spec.get_left()), KP(hj_spec.get_right()));
} else if (OB_FAIL(hj_spec.equal_join_conds_.init(op.get_equal_join_conditions().count()))) {
LOG_WARN("failed to init equal join conditions", K(ret));
} else if (OB_FAIL(generate_rt_exprs(op.get_equal_join_conditions(), hj_spec.equal_join_conds_))) {
LOG_WARN("failed to generate rt exprs", K(ret));
} else if (OB_FAIL(hj_spec.all_join_keys_.init(2 * hj_spec.equal_join_conds_.count()))) {
LOG_WARN("failed to init join keys", K(ret));
} else if (OB_FAIL(hj_spec.all_hash_funcs_.init(2 * hj_spec.equal_join_conds_.count()))) {
LOG_WARN("failed to init join keys", K(ret));
} else {
hj_spec.can_prob_opt_ = true;
for (int64_t i = 0; i < hj_spec.equal_join_conds_.count() && OB_SUCC(ret); ++i) {
ObExpr *expr = hj_spec.equal_join_conds_.at(i);
ObHashFunc left_hash_func;
ObHashFunc right_hash_func;
ObExpr *left_expr = nullptr;
ObExpr *right_expr = nullptr;
bool is_opposite = false;
if (2 != expr->arg_cnt_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: join keys must have 2 arguments", K(ret), K(*expr));
} else if (OB_FAIL(calc_equal_cond_opposite(
op, *op.get_equal_join_conditions().at(i), is_opposite))) {
LOG_WARN("failed to calc equal condition opposite", K(ret));
} else {
if (is_opposite) {
left_expr = expr->args_[1];
right_expr = expr->args_[0];
} else {
left_expr = expr->args_[0];
right_expr = expr->args_[1];
}
if (OB_FAIL(hj_spec.all_join_keys_.push_back(left_expr))) {
LOG_WARN("failed to push back left expr", K(ret));
} else if (OB_FAIL(right_key_exprs.push_back(right_expr))) {
LOG_WARN("failed to push back right expr", K(ret));
} else {
left_hash_func.hash_func_ = left_expr->basic_funcs_->murmur_hash_;
right_hash_func.hash_func_ = right_expr->basic_funcs_->murmur_hash_;
if (OB_ISNULL(left_hash_func.hash_func_) || OB_ISNULL(right_hash_func.hash_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("hash func is null, check datatype is valid", K(ret));
} else if (OB_FAIL(hj_spec.all_hash_funcs_.push_back(left_hash_func))) {
LOG_WARN("failed to push back left expr hash func", K(ret));
} else if (OB_FAIL(right_hash_funcs.push_back(right_hash_func))) {
LOG_WARN("failed to push back right expr hash func", K(ret));
}
}
if (T_REF_COLUMN != left_expr->type_
|| T_REF_COLUMN != right_expr->type_
|| left_expr->datum_meta_.type_ != right_expr->datum_meta_.type_
|| T_OP_NSEQ == expr->type_
|| !has_exist_in_array(hj_spec.get_left()->output_, left_expr)
|| !has_exist_in_array(hj_spec.get_right()->output_, right_expr)) {
hj_spec.can_prob_opt_ = false;
}
}
}
if (hj_spec.can_prob_opt_) {
if (INNER_JOIN != op.get_join_type()
|| op.get_other_join_conditions().count() > 0) {
hj_spec.can_prob_opt_ = false;
}
}
if (OB_SUCC(ret)) {
// 这里暂时不去重,简化后面执行逻辑
if (OB_FAIL(append(hj_spec.all_join_keys_, right_key_exprs))) {
LOG_WARN("failed to append join keys", K(ret));
} else if (OB_FAIL(append(hj_spec.all_hash_funcs_, right_hash_funcs))) {
LOG_WARN("failed to append join keys", K(ret));
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(hj_spec.is_ns_equal_cond_.init(hj_spec.equal_join_conds_.count()))) {
LOG_WARN("failed to init ns equal array", K(ret));
} else {
// for null safe equal, we can not skip null value during executing
for (int64_t i = 0; OB_SUCC(ret) && i < hj_spec.equal_join_conds_.count(); ++i) {
ObExpr *equal_expr = hj_spec.equal_join_conds_.at(i);
if (OB_ISNULL(equal_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("got null join equal expr", K(ret), K(i));
} else if (T_OP_NSEQ == equal_expr->type_) {
OZ (hj_spec.is_ns_equal_cond_.push_back(true));
} else {
OZ (hj_spec.is_ns_equal_cond_.push_back(false));
}
}
}
}
}
}
// level pseudo column as a exec param
/* if (OB_SUCC(ret) && CONNECT_BY_JOIN == op.get_join_type()) {*/
//ObNestedLoopConnectBy *nlj_op = static_cast<ObNestedLoopConnectBy*>(phy_op);
//if (OB_ISNULL(nlj_op)) {
//ret = OB_ERR_NULL_VALUE;
//LOG_WARN("nlj_op is null", K(ret));
//} else if (exec_params.count() == 0) {
//// Do nothing
//} else if (exec_params.count() != 1) {
//// Only one ? expr for all level expr in connent by clause.
//ret = OB_ERR_UNEXPECTED;
//LOG_WARN("unexpected exec params count in connect by", K(exec_params.count()), K(ret));
//} else if (OB_FAIL(nlj_op->init_exec_param_count(exec_params.count()))) {
//LOG_WARN("fail to init param count", K(ret));
//} else {
//ARRAY_FOREACH(exec_params, i) {
//const std::pair<int64_t, ObRawExpr*> &param_expr = exec_params.at(i);
//LOG_DEBUG("connect by", K(param_expr.first), K(param_expr.second), K(ret));
//if (OB_FAIL(nlj_op->add_exec_param(param_expr.first))) {
//LOG_WARN("failed to add nlj param", K(ret));
//}
//}
//}
/*}*/
return ret;
}
int ObStaticEngineCG::do_gi_partition_pruning(
ObLogJoin &op,
ObBasicNestedLoopJoinSpec &spec)
{
int ret = OB_SUCCESS;
OZ(generate_rt_expr(*op.get_partition_id_expr(), spec.gi_partition_id_expr_));
return ret;
}
int ObStaticEngineCG::calc_equal_cond_opposite(const ObLogJoin &op,
const ObRawExpr &raw_expr,
bool &is_opposite)
{
int ret = OB_SUCCESS;
is_opposite = false;
const ObLogicalOperator *left_child = NULL;
const ObLogicalOperator *right_child = NULL;
const ObRawExpr *lexpr = NULL;
const ObRawExpr *rexpr = NULL;
CK(T_OP_EQ == raw_expr.get_expr_type() || T_OP_NSEQ == raw_expr.get_expr_type());
CK(OB_NOT_NULL(left_child = op.get_child(0)));
CK(OB_NOT_NULL(right_child = op.get_child(1)));
CK(OB_NOT_NULL(lexpr = raw_expr.get_param_expr(0)));
CK(OB_NOT_NULL(rexpr = raw_expr.get_param_expr(1)));
if (OB_SUCC(ret)) {
if (lexpr->get_relation_ids().is_subset(left_child->get_table_set())
&& rexpr->get_relation_ids().is_subset(right_child->get_table_set())) {
is_opposite = false;
} else if (lexpr->get_relation_ids().is_subset(right_child->get_table_set())
&& rexpr->get_relation_ids().is_subset(left_child->get_table_set())) {
is_opposite = true;
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid equal condition", K(op), K(raw_expr), K(ret));
}
}
return ret;
}
int ObStaticEngineCG::set_optimization_info(ObLogTableScan &op, ObTableScanSpec &spec)
{
int ret = OB_SUCCESS;
CK(OB_NOT_NULL(phy_plan_));
OZ(spec.set_est_row_count_record(op.get_est_row_count_record()));
if (OB_SUCC(ret)) {
spec.table_row_count_ = op.get_table_row_count();
spec.output_row_count_ = static_cast<int64_t>(op.get_output_row_count());
spec.phy_query_range_row_count_ = static_cast<int64_t>(
op.get_phy_query_range_row_count());
spec.query_range_row_count_ = static_cast<int64_t>(op.get_query_range_row_count());
spec.index_back_row_count_ = static_cast<int64_t>(op.get_index_back_row_count());
}
if (OB_NOT_NULL(op.get_table_opt_info())) {
OZ(spec.set_available_index_name(op.get_table_opt_info()->available_index_name_,
phy_plan_->get_allocator()));
OZ(spec.set_unstable_index_name(op.get_table_opt_info()->unstable_index_name_,
phy_plan_->get_allocator()));
OZ(spec.set_pruned_index_name(op.get_table_opt_info()->pruned_index_name_,
phy_plan_->get_allocator()));
}
return ret;
}
// copy from ObCodeGeneratorImpl
int ObStaticEngineCG::set_partition_range_info(ObLogTableScan &op, ObTableScanSpec &spec)
{
int ret = OB_SUCCESS;
uint64_t table_id = op.get_table_id();
uint64_t ref_table_id = op.get_location_table_id();
uint64_t index_id = op.get_index_table_id();
ObLogPlan *log_plan = op.get_plan();
const ObDMLStmt *stmt = op.get_stmt();
const ObTablePartitionInfo *tbl_part_info = op.get_table_partition_info();
ObSqlSchemaGuard *schema_guard = NULL;
const ObTableSchema *table_schema = NULL;
const ObTableSchema *index_schema = NULL;
ObRawExpr *part_expr = op.get_part_expr();
ObRawExpr *subpart_expr = op.get_subpart_expr();
ObSEArray<ObRawExpr *, 2> part_column_exprs;
ObSEArray<ObRawExpr *, 2> subpart_column_exprs;
ObSEArray<uint64_t, 2> rowkey_column_ids;
if (PHY_MULTI_PART_TABLE_SCAN == spec.type_) {
// do nothing, global index back scan don't has tbl_part_info.
} else if (OB_ISNULL(log_plan) || OB_ISNULL(stmt) || OB_ISNULL(tbl_part_info)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(spec), K(log_plan), K(tbl_part_info), K(stmt), K(ret));
} else if (OB_INVALID_ID == table_id || OB_INVALID_ID == ref_table_id ||
OB_INVALID_ID == index_id) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("invalid table id", K(table_id), K(ref_table_id), K(index_id), K(ret));
} else if (is_virtual_table(ref_table_id)
|| is_inner_table(ref_table_id)
|| is_cte_table(ref_table_id)
|| ObSqlSchemaGuard::is_link_table(op.get_stmt(), table_id)) {
/*do nothing*/
} else if (!stmt->is_select_stmt()
|| tbl_part_info->get_table_location().has_generated_column()) {
/*do nothing*/
} else if (OB_ISNULL(schema_guard = log_plan->get_optimizer_context().get_sql_schema_guard())) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("null schema guard", K(ret));
} else if (OB_FAIL(schema_guard->get_table_schema(table_id, ref_table_id, op.get_stmt(), table_schema))) {
LOG_WARN("get table schema failed", K(table_id), K(ret));
} else if (OB_FAIL(schema_guard->get_table_schema(table_id, index_id, op.get_stmt(), index_schema))) {
LOG_WARN("get index schema failed", K(index_id), K(ret));
} else if (OB_ISNULL(table_schema) || OB_ISNULL(index_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null table schema", K(table_schema), K(index_schema), K(ret));
} else if (!table_schema->is_partitioned_table()) {
/*do nothing*/
} else if (OB_FAIL(index_schema->get_rowkey_info().get_column_ids(rowkey_column_ids))) {
LOG_WARN("failed to get index rowkey column ids", K(ret));
} else if (OB_ISNULL(part_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null part expr", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(part_expr))) { // part expr in table scan need to set IS_COLUMNLIZED flag
LOG_WARN("mark expr self produced failed", K(ret));
} else if (OB_FAIL(ObRawExprUtils::extract_column_exprs(part_expr, part_column_exprs))) {
LOG_WARN("failed to check pure column part expr", K(ret));
} else if (ObPartitionLevel::PARTITION_LEVEL_TWO == table_schema->get_part_level() &&
OB_ISNULL(subpart_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null subpart expr", K(ret));
} else if (NULL != subpart_expr &&
OB_FAIL(ObRawExprUtils::extract_column_exprs(subpart_expr, subpart_column_exprs))) {
LOG_WARN("failed to check pure column part expr", K(ret));
} else if (NULL != subpart_expr
&& OB_FAIL(mark_expr_self_produced(subpart_expr))) { // subpart expr in table scan need to set IS_COLUMNLIZED flag
LOG_WARN("mark expr self produced failed", K(ret));
} else {
bool is_valid = true;
ObSEArray<int64_t, 4> part_range_pos;
ObSEArray<int64_t, 4> subpart_range_pos;
ObSEArray<ObRawExpr *, 4> part_dep_cols;
ObSEArray<ObRawExpr *, 4> subpart_dep_cols;
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < part_column_exprs.count(); i++) {
ObColumnRefRawExpr *col_expr = static_cast<ObColumnRefRawExpr *>(part_column_exprs.at(i));
CK(OB_NOT_NULL(col_expr));
bool is_find = false;
for (int64_t j = 0; OB_SUCC(ret) && !is_find && j < rowkey_column_ids.count(); j++) {
if (col_expr->get_column_id() == rowkey_column_ids.at(j)) {
is_find = true;
OZ(part_range_pos.push_back(j));
OZ(part_dep_cols.push_back(col_expr));
OZ(mark_expr_self_produced(col_expr)); // part range key expr in table scan need to set IS_COLUMNLIZED flag
}
}
if (!is_find) {
is_valid = false;
}
}
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < subpart_column_exprs.count(); i++) {
bool is_find = false;
for (int64_t j = 0; OB_SUCC(ret) && !is_find && j < rowkey_column_ids.count(); j++) {
ObColumnRefRawExpr *col_expr = static_cast<ObColumnRefRawExpr *>(subpart_column_exprs.at(i));
CK(OB_NOT_NULL(col_expr));
if (col_expr->get_column_id() == rowkey_column_ids.at(j)) {
is_find = true;
OZ(subpart_range_pos.push_back(j));
OZ(subpart_dep_cols.push_back(col_expr));
OZ(mark_expr_self_produced(col_expr)); // sub part range key expr in table scan need to set IS_COLUMNLIZED flag
}
}
if (!is_find) {
is_valid = false;
}
}
OZ(generate_rt_exprs(part_dep_cols, spec.part_dep_cols_));
OZ(generate_rt_exprs(subpart_dep_cols, spec.subpart_dep_cols_));
if (OB_SUCC(ret) && is_valid) {
if (NULL != part_expr) {
OZ(generate_rt_expr(*part_expr, spec.part_expr_));
}
if (NULL != subpart_expr) {
OZ(generate_rt_expr(*subpart_expr, spec.subpart_expr_));
}
OZ(spec.part_range_pos_.assign(part_range_pos));
OZ(spec.subpart_range_pos_.assign(subpart_range_pos));
spec.part_level_ = table_schema->get_part_level();
spec.part_type_ = table_schema->get_part_option().get_part_func_type();
spec.subpart_type_ = table_schema->get_sub_part_option().get_part_func_type();
LOG_DEBUG("partition range pos", K(table_schema->get_part_level()),
K(part_range_pos), K(subpart_range_pos), K(ret));
}
}
return ret;
}
// 递归地找出column expr在generated table中对应的基表的column expr
int ObStaticEngineCG::recursive_get_column_expr(const ObColumnRefRawExpr *&column,
const TableItem &table_item)
{
int ret = OB_SUCCESS;
const ObSelectStmt *stmt = table_item.ref_query_;
const ObRawExpr *select_expr = NULL;
if (OB_ISNULL(column) || OB_ISNULL(stmt) || OB_ISNULL(stmt = stmt->get_real_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(column), K(stmt));
} else {
const int64_t offset = column->get_column_id() - OB_APP_MIN_COLUMN_ID;
if (OB_UNLIKELY(offset < 0 || offset >= stmt->get_select_item_size()) ||
OB_ISNULL(select_expr = stmt->get_select_item(offset).expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected select expr", K(ret),
K(offset), K(stmt->get_select_item_size()), K(select_expr));
} else if (OB_UNLIKELY(!select_expr->is_column_ref_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected expr", K(ret), K(*select_expr));
} else {
const ObColumnRefRawExpr *inner_column = static_cast<const ObColumnRefRawExpr *>(select_expr);
const TableItem *table_item = stmt->get_table_item_by_id(inner_column->get_table_id());
if (OB_ISNULL(table_item)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if ((table_item->is_generated_table() || table_item->is_temp_table()) &&
OB_FAIL(recursive_get_column_expr(inner_column, *table_item))) {
LOG_WARN("faield to recursive get column expr", K(ret));
} else {
column = inner_column;
}
}
}
return ret;
}
int ObStaticEngineCG::add_update_set(ObSubPlanFilterSpec &spec)
{
int ret = OB_SUCCESS;
ObSEArray<ObExpr*, 8> all_output_exprs;
const int64_t child_cnt = spec.get_child_cnt();
ObOpSpec *child_spec = NULL;
for (int64_t i = 1; OB_SUCC(ret) && i < child_cnt; ++i) {
if (OB_ISNULL(child_spec = spec.get_children()[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected NULL", K(ret), K(child_spec));
} else if (OB_FAIL(append(all_output_exprs, child_spec->output_))) {
LOG_WARN("failed to append child output.", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_UNLIKELY(all_output_exprs.count() + 1 < child_cnt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected child output exprs size", K(ret), K(all_output_exprs.count()),
K(child_cnt));
} else if (OB_FAIL(spec.update_set_.assign(all_output_exprs))) {
LOG_WARN("failed to assign update set", K(ret));
} else {
LOG_DEBUG("add update set", K(spec.update_set_.count()));
}
return ret;
}
int ObStaticEngineCG::generate_spec(
ObLogSubPlanFilter &op, ObSubPlanFilterSpec &spec, const bool)
{
int ret = OB_SUCCESS;
if (op.is_update_set() && OB_FAIL(add_update_set(spec))) {
LOG_WARN("failed to add update set", K(ret));
}
CK(NULL != op.get_plan() && NULL != op.get_plan()->get_stmt());
if (OB_SUCC(ret)) {
const ObIArray<ObExecParamRawExpr *> *exec_params[] = {
&op.get_exec_params(), &op.get_onetime_exprs()
};
ObFixedArray<ObDynamicParamSetter, ObIAllocator> *setters[] = {
&spec.rescan_params_, &spec.onetime_exprs_
};
static_assert(ARRAYSIZEOF(exec_params) == ARRAYSIZEOF(setters),
"array count mismatch");
for (int64_t i = 0; OB_SUCC(ret) && i < ARRAYSIZEOF(exec_params); i++) {
OZ(generate_param_spec(*exec_params[i], *setters[i]));
}
}
if (OB_SUCC(ret)) {
OZ(spec.one_time_idxs_.add_members2(op.get_onetime_idxs()));
OZ(spec.init_plan_idxs_.add_members2(op.get_initplan_idxs()));
}
//set exec_param idx depended
if (OB_SUCC(ret)) {
//add all right children there
int64_t subquery_cnt = spec.get_child_cnt() - 1;
if (OB_FAIL(spec.exec_param_array_.init(subquery_cnt))) {
LOG_WARN("failed to init exec param array", K(ret));
} else {
ObFixedArray<ObExpr *, ObIAllocator> cache_vec(phy_plan_->get_allocator());
for (int64_t child_idx = 1; OB_SUCC(ret) && child_idx < spec.get_child_cnt(); ++child_idx) {
SubPlanInfo *sp_info = nullptr;
ObLogicalOperator *curr_child = nullptr;
if (OB_ISNULL(curr_child = op.get_child(child_idx))
|| OB_ISNULL(curr_child->get_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to get subplan filter child", K(child_idx), K(ret));
} else if (OB_FAIL(op.get_plan()->get_subplan(curr_child->get_stmt(), sp_info))) {
LOG_WARN("failed to get subplan info for this child", K(ret), K(child_idx));
} else if (OB_ISNULL(sp_info) || OB_ISNULL(sp_info->init_expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sp info is invalid", K(ret), K(sp_info));
} else {
cache_vec.reset();
if (OB_FAIL(cache_vec.init(sp_info->init_expr_->get_param_count()))) {
LOG_WARN("failed to init tmp_vec", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < sp_info->init_expr_->get_param_count(); ++j) {
ObExecParamRawExpr *exec_param = sp_info->init_expr_->get_exec_param(j);
ObExpr *rt_expr = nullptr;
CK(nullptr != exec_param);
//OX(rt_expr = ObStaticEngineExprCG::get_rt_expr(*param_expr));
OZ(generate_rt_expr(*exec_param, rt_expr));
OZ(cache_vec.push_back(rt_expr));
}
if (OB_SUCC(ret)) {
OZ(spec.exec_param_array_.push_back(cache_vec));
}
}
}
OX(spec.exec_param_idxs_inited_ = true);
}
}
// set enable px batch rescan infos
if (OB_SUCC(ret)) {
if (OB_FAIL(spec.init_px_batch_rescan_flags(spec.get_child_cnt()))) {
LOG_WARN("fail to init px batch rescan flags", K(ret));
} else {
ObIArray<bool> &enable_op_px_batch_flags = op.get_px_batch_rescans();
ObIArray<bool> &enable_phy_px_batch_flags = spec.enable_px_batch_rescans_;
if (!enable_op_px_batch_flags.empty() &&
enable_op_px_batch_flags.count() != spec.get_child_cnt()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("batch flag's count is unexpected", K(ret));
} else {
for (int i = 0; i < spec.get_child_cnt() && OB_SUCC(ret); ++i) {
if (enable_op_px_batch_flags.empty()) {
enable_phy_px_batch_flags.push_back(false);
} else if (OB_FAIL(enable_phy_px_batch_flags.push_back(
enable_op_px_batch_flags.at(i)))) {
LOG_WARN("fail to push back batch flag", K(ret));
}
}
}
}
}
if (OB_SUCC(ret)) {
spec.enable_das_batch_rescans_ = op.get_enable_das_batch_rescans();
}
return ret;
}
int ObStaticEngineCG::generate_spec(
ObLogSubPlanScan &op, ObSubPlanScanSpec &spec, const bool)
{
int ret = OB_SUCCESS;
ObLogicalOperator *child = op.get_child(0);
CK(NULL != child);
OZ(spec.projector_.init(op.get_access_exprs().count() * 2));
FOREACH_CNT_X(e, op.get_access_exprs(), OB_SUCC(ret)) {
CK(NULL != *e);
CK((*e)->is_column_ref_expr());
const ObColumnRefRawExpr *col_expr = static_cast<ObColumnRefRawExpr *>(*e);
if (OB_SUCC(ret)) {
// for generate table column_id is generated by OB_APP_MIN_COLUMN_ID + select_item_index
int64_t idx = col_expr->get_column_id() - OB_APP_MIN_COLUMN_ID;
CK(idx >= 0);
CK(idx < child->get_output_exprs().count());
CK(NULL != child->get_output_exprs().at(idx));
if (OB_SUCC(ret)) {
const ObRawExpr *from = child->get_output_exprs().at(idx);
ObExpr *rt_expr = NULL;
ObObjType from_type = from->get_result_type().get_type();
ObObjType to_type = col_expr->get_result_type().get_type();
ObCollationType from_coll = from->get_result_type().get_collation_type();
ObCollationType to_coll = col_expr->get_result_type().get_collation_type();
if (OB_UNLIKELY(ob_obj_type_class(from_type) != ob_obj_type_class(to_type) ||
(ob_is_string_or_lob_type(from_type) && from_coll != to_coll))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected output type of subplan scan", K(ret), K(from->get_result_type()),
K(col_expr->get_result_type()));
}
OZ(generate_rt_expr(*from, rt_expr));
OZ(spec.projector_.push_back(rt_expr));
OZ(generate_rt_expr(*col_expr, rt_expr));
OZ(spec.projector_.push_back(rt_expr));
OZ(mark_expr_self_produced(*e)); // table access exprs in convert_subplan_scan need to set IS_COLUMNLIZED flag
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogErrLog &op,
ObErrLogSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
stmt::StmtType stmt_type = stmt::StmtType::T_INSERT;
UNUSED(in_root_job);
if (OB_FAIL(dml_cg_service_.generate_err_log_ctdef(op.get_err_log_define(), spec.err_log_ct_def_))) {
LOG_WARN("fail to cg err_log_ctdef", K(ret));
} else if (OB_FAIL(op.get_err_log_type(stmt_type))) {
LOG_WARN("fail get error logging stmt type", K(ret));
} else {
ObDASOpType type = DAS_OP_TABLE_INSERT;
switch(stmt_type) {
case stmt::StmtType::T_INSERT:
type = DAS_OP_TABLE_INSERT;
break;
case stmt::StmtType::T_UPDATE:
type = DAS_OP_TABLE_UPDATE;
break;
default:
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect stmt type");
break;
}
spec.type_ = type;
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTableLookup &op, ObTableLookupSpec &spec, const bool)
{
int ret = OB_SUCCESS;
ObSqlSchemaGuard *schema_guard = NULL;
const ObTableSchema *table_schema = NULL;
ObSQLSessionInfo *my_session = NULL;
if (OB_ISNULL(op.get_plan()) ||
OB_ISNULL(schema_guard = op.get_plan()->get_optimizer_context().get_sql_schema_guard())) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("get unexpected null", K(schema_guard), K(ret));
} else if (OB_FAIL(schema_guard->get_table_schema(op.get_table_id(), op.get_ref_table_id(),
op.get_stmt(), table_schema))) {
LOG_WARN("failed to get table schema", K(ret));
} else if (OB_ISNULL(my_session = op.get_plan()->get_optimizer_context().get_session_info())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null session", K(ret));
} else if (OB_ISNULL(table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null table schema", K(ret));
} else {
spec.scan_ctdef_.ref_table_id_ = op.get_ref_table_id();
spec.batch_rescan_ = op.use_batch();
spec.scan_ctdef_.schema_version_ = table_schema->get_schema_version();
// for calc partition id expr
if (OB_FAIL(tsc_cg_service_.generate_table_loc_meta(op.get_table_id(),
*op.get_stmt(),
*table_schema,
*my_session,
spec.loc_meta_))) {
LOG_WARN("generate table loc meta failed", K(ret));
} else if (OB_ISNULL(op.get_calc_part_id_expr())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("repart_transmit's calc_part_id_expr is null", K(ret));
} else if (OB_FAIL(generate_calc_part_id_expr(*op.get_calc_part_id_expr(),
&spec.loc_meta_,
spec.calc_part_id_expr_))) {
LOG_WARN("fail to generate calc part id expr", K(ret), KP(op.get_calc_part_id_expr()));
} else if (spec.batch_rescan_) {
if (OB_FAIL(generate_rt_expr(*op.get_group_id_expr(), spec.scan_ctdef_.group_id_expr_))) {
LOG_WARN("generate group id expr failed", K(ret));
}
}
const ObIArray<ObRawExpr*> &access_exprs = op.get_access_exprs();
if (OB_SUCC(ret)) {
// table access in index table scan need to set IS_COLUMNLIZED flag
if (OB_FAIL(mark_expr_self_produced(access_exprs))) {
LOG_WARN("mark expr self produced failed", K(ret));
}
}
if (OB_SUCC(ret)) {
//使用DAS方式执行,去掉ObTableLookup中的Mini subplan,直接将回表的output信息记录在table lookup上
OZ(spec.scan_ctdef_.access_column_ids_.init(access_exprs.count()));
OZ(generate_rt_exprs(access_exprs, spec.scan_ctdef_.pd_expr_spec_.access_exprs_));
if (OB_SUCC(ret) && (OB_NOT_NULL(op.get_flashback_query_expr()))) {
OZ(generate_rt_expr(*op.get_flashback_query_expr(),
spec.flashback_item_.flashback_query_expr_));
OX(spec.flashback_item_.flashback_query_type_ = op.get_flashback_query_type());
}
ARRAY_FOREACH(access_exprs, i) {
ObRawExpr *expr = access_exprs.at(i);
uint64_t column_id = 0;
if (OB_UNLIKELY(OB_ISNULL(expr))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null", K(ret));
} else if (T_ORA_ROWSCN == expr->get_expr_type()) {
column_id = common::OB_HIDDEN_TRANS_VERSION_COLUMN_ID;
spec.flashback_item_.need_scn_ = true;
LOG_DEBUG("need row scn");
} else if (T_PSEUDO_GROUP_ID == expr->get_expr_type()) {
column_id = common::OB_HIDDEN_GROUP_IDX_COLUMN_ID;
} else {
ObColumnRefRawExpr* col_expr = static_cast<ObColumnRefRawExpr *>(expr);
if (!col_expr->has_flag(IS_COLUMN)
|| col_expr->get_table_id() != op.get_table_id()) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("Expected basic column", K(col_expr), K(col_expr->has_flag(IS_COLUMN)),
K(col_expr->get_table_id()), K(op.get_table_id()));
} else {
column_id = col_expr->get_column_id();
}
}
OZ(spec.scan_ctdef_.access_column_ids_.push_back(column_id));
} // end for
CK(!op.get_rowkey_exprs().empty());
OZ(generate_rt_exprs(op.get_rowkey_exprs(), spec.rowkey_exprs_));
}
}
OZ(spec.scan_ctdef_.table_param_.convert(*table_schema, spec.scan_ctdef_.access_column_ids_));
OZ(tsc_cg_service_.generate_das_result_output(spec.scan_ctdef_.access_column_ids_, spec.scan_ctdef_));
#ifndef NDEBUG
if (OB_SUCC(ret)) {
// debug
LOG_DEBUG("operator generate", K(op), K(spec.batch_rescan_));
}
#endif
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTableScan &op, ObRowSampleScanSpec &spec, const bool)
{
int ret = OB_SUCCESS;
OZ(generate_normal_tsc(op, spec));
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTableScan &op, ObBlockSampleScanSpec &spec, const bool)
{
int ret = OB_SUCCESS;
OZ(generate_normal_tsc(op, spec));
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogTableScan &op, ObTableScanWithIndexBackSpec &spec,
const bool)
{
int ret = OB_SUCCESS;
OZ(generate_normal_tsc(op, spec));
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogDelete &op,
ObPxMultiPartDeleteSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (op.get_num_of_child() < 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("child num is error", K(ret));
} else if (OB_UNLIKELY(op.get_index_dml_infos().count() != 1) ||
OB_ISNULL(op.get_index_dml_infos().at(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("the count of dml index info is error", K(ret));
} else {
const IndexDMLInfo &index_dml_info = *op.get_index_dml_infos().at(0);
phy_plan_->set_use_pdml(true);
spec.is_returning_ = op.pdml_is_returning();
spec.set_with_barrier(op.need_barrier());
spec.is_pdml_index_maintain_ = op.is_index_maintenance();
spec.is_pdml_update_split_ = op.is_pdml_update_split();
int64_t partition_expr_idx = OB_INVALID_INDEX;
if (OB_FAIL(get_pdml_partition_id_column_idx(spec.get_child(0)->output_, partition_expr_idx))) {
LOG_WARN("failed to get partition id column idx", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_delete_ctdef(op, index_dml_info, spec.del_ctdef_))) {
LOG_WARN("generate delete ctdef failed", K(ret));
} else {
spec.row_desc_.set_part_id_index(partition_expr_idx);
}
LOG_TRACE("pdml static cg information", K(ret), K(partition_expr_idx), K(index_dml_info));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogInsert &op,
ObPxMultiPartInsertSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_UNLIKELY(op.get_index_dml_infos().count() != 1) ||
OB_ISNULL(op.get_index_dml_infos().at(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info is invalid", K(ret), K(op.get_index_dml_infos().count()));
} else {
const IndexDMLInfo &index_dml_info = *op.get_index_dml_infos().at(0);
phy_plan_->set_use_pdml(true);
spec.is_returning_ = op.pdml_is_returning();
spec.is_pdml_index_maintain_ = op.is_index_maintenance();
spec.table_location_uncertain_ = op.is_table_location_uncertain(); // row-movement target table
spec.is_pdml_update_split_ = op.is_pdml_update_split();
int64_t partition_expr_idx = OB_INVALID_INDEX;
if (OB_FAIL(get_pdml_partition_id_column_idx(spec.get_child(0)->output_, partition_expr_idx))) {
LOG_WARN("failed to get partition id column idx", K(ret));
} else {
spec.row_desc_.set_part_id_index(partition_expr_idx);
}
LOG_TRACE("pdml static cg information", K(ret), K(partition_expr_idx), K(index_dml_info));
// 处理pdml-insert中的insert_row_exprs
OZ(dml_cg_service_.generate_insert_ctdef(op, index_dml_info, spec.ins_ctdef_));
// table columns exprs in dml need to set IS_COLUMNLIZED flag
OZ(mark_expr_self_produced(index_dml_info.column_exprs_));
OZ(mark_expr_self_produced(index_dml_info.column_convert_exprs_));
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogInsert &op, ObPxMultiPartSSTableInsertSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
const ObExecContext *exec_ctx = nullptr;
ObLogPlan *log_plan = nullptr;
if (OB_FAIL(generate_spec(op, static_cast<ObPxMultiPartInsertSpec &>(spec), in_root_job))) {
LOG_WARN("generge multi part sstable insert spec failed", K(ret));
} else if (OB_ISNULL(log_plan = op.get_plan()) ||
OB_ISNULL(exec_ctx = log_plan->get_optimizer_context().get_exec_ctx())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), KP(log_plan), KP(exec_ctx));
} else {
ObSqlCtx *sql_ctx = const_cast<ObExecContext *>(exec_ctx)->get_sql_ctx();
if (OB_FAIL(generate_rt_expr(*sql_ctx->flashback_query_expr_, spec.flashback_query_expr_))) {
LOG_WARN("generate rt expr failed", K(ret));
} else if (log_plan->get_optimizer_context().is_heap_table_ddl()) {
spec.regenerate_heap_table_pk_ = true;
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogUpdate &op,
ObPxMultiPartUpdateSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_UNLIKELY(op.get_index_dml_infos().count() != 1) ||
OB_ISNULL(op.get_index_dml_infos().at(0))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info is invalid", K(ret), K(op.get_index_dml_infos().count()));
} else {
phy_plan_->set_use_pdml(true);
spec.is_returning_ = op.pdml_is_returning();
spec.is_pdml_index_maintain_ = op.is_index_maintenance();
const IndexDMLInfo &index_dml_info = *op.get_index_dml_infos().at(0);
spec.is_ignore_ = op.is_ignore();
phy_plan_->set_ignore(op.is_ignore());
int64_t partition_expr_idx = OB_INVALID_INDEX;
if (OB_FAIL(get_pdml_partition_id_column_idx(spec.get_child(0)->output_, partition_expr_idx))) {
LOG_WARN("failed to get partition id column idx", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_update_ctdef(op, index_dml_info, spec.upd_ctdef_))) {
LOG_WARN("generate pdml update ctdef failed", K(ret));
} else {
spec.row_desc_.set_part_id_index(partition_expr_idx);
}
LOG_TRACE("pdml static cg information", K(ret), K(partition_expr_idx), K(index_dml_info));
// table columns exprs in dml need to set IS_COLUMNLIZED flag
OZ(mark_expr_self_produced(index_dml_info.column_exprs_));
}
return ret;
}
int ObStaticEngineCG::fill_aggr_infos(ObLogGroupBy &op,
ObGroupBySpec &spec,
common::ObIArray<ObExpr *> *group_exprs/*NULL*/,
common::ObIArray<ObExpr *> *rollup_exprs/*NULL*/,
common::ObIArray<ObExpr *> *distinct_exprs/*NULL*/)
{
int ret = OB_SUCCESS;
CK(NULL != phy_plan_);
const ObIArray<ObRawExpr*> &aggr_exprs = op.get_aggr_funcs();
//1.init aggr expr
ObSEArray<ObExpr *, 8> all_aggr_exprs;
ARRAY_FOREACH(aggr_exprs, i) {
ObRawExpr *raw_expr = NULL;
ObExpr *expr = NULL;
if (OB_ISNULL(raw_expr = aggr_exprs.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("raw_expr is null ", K(ret), K(expr));
} else if (OB_UNLIKELY(!raw_expr->has_flag(IS_AGG))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expected aggr function", K(ret));
} else if (OB_FAIL(mark_expr_self_produced(raw_expr))) { // aggr func exprs in group by need to set IS_COLUMNLIZED flag
LOG_WARN("add columnlized flag to agg expr failed", K(ret));
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else if (OB_FAIL(all_aggr_exprs.push_back(expr))) {
LOG_WARN("Add var to array error", K(ret));
}
}
// 2.init non aggr expr
// oracle mode has the non aggregation expr problem too:
//
// explain extended select abs(c1), sum(c2) from t1 group by abs(c1);
// | ========================================
// |ID|OPERATOR |NAME|EST. ROWS|COST |
// ----------------------------------------
// |0 |HASH GROUP BY| |101 |106673|
// |1 | TABLE SCAN |T1 |100000 |68478 |
// ========================================
//
// Outputs & filters:
// -------------------------------------
// 0 - output([ABS(T1.C1(0x7f1aa0c43580))(0x7f1aa0c45850)], [T_FUN_SUM(T1.C2(0x7f1aa0c489e0))(0x7f1aa0c48410)]), filter(nil),
// group([ABS(T1.C1(0x7f1aa0c43580))(0x7f1aa0c42a20)]), agg_func([T_FUN_SUM(T1.C2(0x7f1aa0c489e0))(0x7f1aa0c48410)])
// 1 - output([T1.C1(0x7f1aa0c43580)], [T1.C2(0x7f1aa0c489e0)], [ABS(T1.C1(0x7f1aa0c43580))(0x7f1aa0c42a20)]), filter(nil),
// access([T1.C1(0x7f1aa0c43580)], [T1.C2(0x7f1aa0c489e0)]), partitions(p0),
//
// The output abs(c1) 0x7f1aa0c45850 is not the group by column (raw expr not the same),
// (the resolver will correct this in future). We need the mysql non aggregate output
// feature to evaluate it.
ObSEArray<ObExpr *, 8> all_non_aggr_exprs;
common::ObIArray<ObExpr *> &child_output = spec.get_children()[0]->output_;
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_output_exprs().count(); ++i) {
ObExpr *expr = NULL;
const ObRawExpr &raw_expr = *op.get_output_exprs().at(i);
if (OB_FAIL(generate_rt_expr(raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("expr is null ", K(ret), K(expr));
} else if (OB_FAIL(extract_non_aggr_expr(expr,
&raw_expr,
child_output,
all_aggr_exprs,
group_exprs,
rollup_exprs,
distinct_exprs,
all_non_aggr_exprs))) {
OB_LOG(WARN, "fail to extract_non_aggr_expr", "count", all_non_aggr_exprs.count(),
KPC(expr), K(ret));
} else {
OB_LOG(DEBUG, "finish extract_non_aggr_expr", KPC(expr), K(raw_expr), K(child_output),
K(all_aggr_exprs), KPC(group_exprs), KPC(rollup_exprs), K(all_non_aggr_exprs));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_filter_exprs().count(); ++i) {
ObExpr *expr = NULL;
const ObRawExpr &raw_expr = *op.get_filter_exprs().at(i);
if (OB_FAIL(generate_rt_expr(raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("expr is null ", K(ret), K(expr));
} else if (OB_FAIL(extract_non_aggr_expr(expr,
&raw_expr,
child_output,
all_aggr_exprs,
group_exprs,
rollup_exprs,
distinct_exprs,
all_non_aggr_exprs))) {
OB_LOG(WARN, "fail to extract_non_aggr_expr", "count", all_non_aggr_exprs.count(),
KPC(expr), K(ret));
} else {
OB_LOG(DEBUG, "finish extract_non_aggr_expr", KPC(expr), K(raw_expr), K(child_output),
K(all_aggr_exprs), KPC(group_exprs), KPC(rollup_exprs), K(all_non_aggr_exprs));
}
}
//3.init aggr_infos
if (OB_SUCC(ret)) {
if (OB_FAIL(spec.aggr_infos_.prepare_allocate(
all_aggr_exprs.count() + all_non_aggr_exprs.count()))) {
OB_LOG(WARN, "fail to prepare_allocate aggr_infos_", K(ret));
}
}
//4.add aggr columns
spec.support_fast_single_row_agg_ = true;
for (int64_t i = 0; OB_SUCC(ret) && i < all_aggr_exprs.count(); ++i) {
ObAggrInfo &aggr_info = spec.aggr_infos_.at(i);
if (!is_simple_aggr_expr(aggr_exprs.at(i)->get_expr_type())) {
spec.support_fast_single_row_agg_ = false;
}
if (OB_FAIL(fill_aggr_info(*static_cast<ObAggFunRawExpr *>(aggr_exprs.at(i)),
*all_aggr_exprs.at(i),
aggr_info,
group_exprs,
rollup_exprs))) {
LOG_WARN("failed to fill_aggr_info", K(ret));
}
}//end of for
//5. file non_aggr_expr
for (int64_t i = 0; OB_SUCC(ret) && i < all_non_aggr_exprs.count(); ++i) {
ObExpr *expr = all_non_aggr_exprs.at(i);
ObAggrInfo &aggr_info = spec.aggr_infos_.at(all_aggr_exprs.count() + i);
aggr_info.set_implicit_first_aggr();
aggr_info.expr_ = expr;
LOG_TRACE("trace all non aggr exprs", K(*expr), K(all_non_aggr_exprs.count()));
}
return ret;
}
int ObStaticEngineCG::fill_aggr_info(ObAggFunRawExpr &raw_expr,
ObExpr &expr, ObAggrInfo &aggr_info,
common::ObIArray<ObExpr *> *group_exprs/*NULL*/,
common::ObIArray<ObExpr *> *rollup_exprs/*NULL*/)
{
int ret = OB_SUCCESS;
if (T_FUN_TOP_FRE_HIST == raw_expr.get_expr_type() &&
OB_FAIL(generate_top_fre_hist_expr_operator(raw_expr, aggr_info))) {
LOG_WARN("failed to generate_top_fre_hist_expr_operator", K(ret));
} else if (T_FUN_HYBRID_HIST == raw_expr.get_expr_type() &&
OB_FAIL(generate_hybrid_hist_expr_operator(raw_expr, aggr_info))) {
LOG_WARN("failed to generate_top_fre_hist_expr_operator", K(ret));
} else {
const int64_t group_concat_param_count =
(is_oracle_mode()
&& raw_expr.get_expr_type() == T_FUN_GROUP_CONCAT
&& raw_expr.get_real_param_count() > 1)
? (raw_expr.get_real_param_count() - 1)
: raw_expr.get_real_param_count();
aggr_info.expr_ = &expr;
aggr_info.has_distinct_ = raw_expr.is_param_distinct();
aggr_info.group_concat_param_count_ = group_concat_param_count;
if (aggr_info.has_distinct_) {
if (OB_FAIL(aggr_info.distinct_collations_.init(group_concat_param_count))) {
LOG_WARN("failed to init distinct_collations_", K(ret));
} else if (OB_FAIL(aggr_info.distinct_cmp_funcs_.init(group_concat_param_count))) {
LOG_WARN("failed to init distinct_cmp_funcs_", K(ret));
}
}
//set pl agg udf info
if (OB_SUCC(ret) && T_FUN_PL_AGG_UDF == raw_expr.get_expr_type()) {
if (OB_ISNULL(raw_expr.get_pl_agg_udf_expr()) ||
OB_UNLIKELY(!raw_expr.get_pl_agg_udf_expr()->is_udf_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(raw_expr.get_pl_agg_udf_expr()));
} else if (OB_FAIL(aggr_info.pl_agg_udf_params_type_.init(group_concat_param_count))) {
LOG_WARN("failed to init pl_agg_udf_params_type_", K(ret));
} else {
ObUDFRawExpr *udf_expr = static_cast<ObUDFRawExpr *>(raw_expr.get_pl_agg_udf_expr());
aggr_info.pl_agg_udf_type_id_ = udf_expr->get_type_id();
aggr_info.pl_result_type_ = const_cast<ObExprResType &>(raw_expr.get_result_type());
}
}
// mysql dll udf
if (OB_SUCC(ret) && T_FUN_AGG_UDF == raw_expr.get_expr_type()) {
aggr_info.dll_udf_ = OB_NEWx(ObAggDllUdfInfo, aggr_info.alloc_,
(*aggr_info.alloc_), raw_expr.get_expr_type());
OZ(aggr_info.dll_udf_->from_raw_expr(raw_expr));
}
ObSEArray<ObExpr*, 16> all_param_exprs;
if (OB_SUCC(ret)) {
const ObOrderDirection order_direction = default_asc_direction();
const bool is_ascending = is_ascending_direction(order_direction);
const common::ObCmpNullPos null_pos = ((is_null_first(order_direction) ^ is_ascending)
? NULL_LAST : NULL_FIRST);
for (int64_t i = 0; OB_SUCC(ret) && i < group_concat_param_count; ++i) {
ObExpr *expr = NULL;
const ObRawExpr &param_raw_expr = *raw_expr.get_real_param_exprs().at(i);
if (OB_FAIL(generate_rt_expr(param_raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else if ((T_FUN_GROUP_CONCAT == raw_expr.get_expr_type() ||
T_FUN_KEEP_WM_CONCAT == raw_expr.get_expr_type() ||
T_FUN_WM_CONCAT == raw_expr.get_expr_type())
&& OB_UNLIKELY(!param_raw_expr.get_result_meta().is_string_type())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("param_raw_expr is not sting ", K(ret), K(param_raw_expr));
} else if (OB_FAIL(all_param_exprs.push_back(expr))) {
LOG_WARN("failed to push_back param_expr", K(ret));
} else if (T_FUN_PL_AGG_UDF == raw_expr.get_expr_type() &&
OB_FAIL(aggr_info.pl_agg_udf_params_type_.push_back(
const_cast<ObExprResType &>(param_raw_expr.get_result_type())))) {
LOG_WARN("failed to push_back expr type", K(ret));
} else if (aggr_info.has_distinct_) {
ObSortFieldCollation field_collation(i, expr->datum_meta_.cs_type_, is_ascending, null_pos);
ObSortCmpFunc cmp_func;
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(expr->datum_meta_.type_,
expr->datum_meta_.type_,
field_collation.null_pos_,
field_collation.cs_type_,
lib::is_oracle_mode());
if (OB_ISNULL(cmp_func.cmp_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp_func is null, check datatype is valid", K(ret));
} else if (OB_FAIL(aggr_info.distinct_collations_.push_back(field_collation))) {
LOG_WARN("failed to push back field collation", K(ret));
} else if (OB_FAIL(aggr_info.distinct_cmp_funcs_.push_back(cmp_func))) {
LOG_WARN("failed to push back cmp function", K(ret));
} else {
LOG_DEBUG("succ to push back field collation", K(field_collation), K(i));
}
}
}
}
if (OB_SUCC(ret) && (T_FUN_GROUP_CONCAT == raw_expr.get_expr_type() ||
T_FUN_GROUP_RANK == raw_expr.get_expr_type() ||
T_FUN_GROUP_DENSE_RANK == raw_expr.get_expr_type() ||
T_FUN_GROUP_PERCENT_RANK == raw_expr.get_expr_type() ||
T_FUN_GROUP_CUME_DIST == raw_expr.get_expr_type() ||
T_FUN_GROUP_PERCENTILE_CONT == raw_expr.get_expr_type() ||
T_FUN_GROUP_PERCENTILE_DISC == raw_expr.get_expr_type() ||
T_FUN_MEDIAN == raw_expr.get_expr_type() ||
T_FUN_KEEP_SUM == raw_expr.get_expr_type() ||
T_FUN_KEEP_MAX == raw_expr.get_expr_type() ||
T_FUN_KEEP_MIN == raw_expr.get_expr_type() ||
T_FUN_KEEP_COUNT == raw_expr.get_expr_type() ||
T_FUN_KEEP_WM_CONCAT == raw_expr.get_expr_type() ||
T_FUN_HYBRID_HIST == raw_expr.get_expr_type())) {
const ObRawExpr *param_raw_expr = (is_oracle_mode()
&& T_FUN_GROUP_CONCAT == raw_expr.get_expr_type()
&& raw_expr.get_real_param_count() > 1)
? raw_expr.get_real_param_exprs().at(raw_expr.get_real_param_count() - 1)
: raw_expr.get_separator_param_expr();
if (param_raw_expr != NULL) {
ObExpr *expr = NULL;
if (OB_FAIL(generate_rt_expr(*param_raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else if (OB_UNLIKELY(!expr->obj_meta_.is_string_type())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr node is null", K(ret), KPC(expr));
} else {
aggr_info.separator_expr_ = expr;
}
}
if (OB_SUCC(ret) && !raw_expr.get_order_items().empty()) {
aggr_info.has_order_by_ = true;
if (OB_FAIL(fil_sort_info(raw_expr.get_order_items(),
all_param_exprs,
NULL,
aggr_info.sort_collations_,
aggr_info.sort_cmp_funcs_))) {
LOG_WARN("failed to fil_sort_info", K(ret));
} else {/*do nothing*/}
}//order item
}//group concat
// The argment of grouping is index in rollup exprs
if (OB_SUCC(ret) && OB_NOT_NULL(rollup_exprs) &&
T_FUN_GROUPING == raw_expr.get_expr_type() && 0 < rollup_exprs->count()) {
bool match = false;
ObExpr *arg_expr = expr.args_[0];
for (int64_t expr_idx = 0; !match && expr_idx < group_exprs->count(); expr_idx++) {
if (arg_expr == group_exprs->at(expr_idx)) {
match = true;
}
}
for (int64_t expr_idx = 0; !match && expr_idx < rollup_exprs->count(); expr_idx++) {
if (arg_expr == rollup_exprs->at(expr_idx)) {
match = true;
aggr_info.rollup_idx_ = expr_idx + group_exprs->count();
}
}
if (OB_SUCC(ret) && !match) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected status: the argument of grouping is invalid", K(ret));
}
}
// The arguments of grouping_id are the indexs in rollup exprs.
aggr_info.grouping_idxs_.init(expr.arg_cnt_);
if (OB_SUCC(ret) && OB_NOT_NULL(rollup_exprs) &&
T_FUN_GROUPING_ID == raw_expr.get_expr_type() && rollup_exprs->count() > 0) {
for (int64_t i = 0; OB_SUCC(ret) && i < expr.arg_cnt_; i++) {
int64_t expr_idx = OB_INVALID_INDEX;
ObExpr *arg_expr = expr.args_[i];
if (has_exist_in_array(*group_exprs, arg_expr, &expr_idx)) {
if (OB_FAIL(aggr_info.grouping_idxs_.push_back(expr_idx))) {
LOG_WARN("push_back fail", K(ret));
}
}
if (expr_idx == OB_INVALID_INDEX && has_exist_in_array(*rollup_exprs, arg_expr, &expr_idx)) {
if (OB_FAIL(aggr_info.grouping_idxs_.push_back(group_exprs->count() + expr_idx))) {
LOG_WARN("push_back fail", K(ret));
}
}
if (OB_SUCC(ret) && expr_idx == OB_INVALID_INDEX) {
ret = OB_ERR_WRONG_FIELD_WITH_GROUP;
LOG_WARN("unexpected status: the argument of grouping_id is invalid");
}
}
}
//group_id()
ObSEArray<int64_t,10> group_id_array;
if (OB_SUCC(ret) && T_FUN_GROUP_ID == raw_expr.get_expr_type()) {
if (OB_ISNULL(group_exprs)) {
// oracle raise error: ORA-30481: GROUPING function only supported with GROUP BY CUBE or ROLLUP
ret = OB_ERR_UNEXPECTED;
LOG_WARN("grouping_id shouldn't appear if there were no groupby");
} else if (OB_NOT_NULL(rollup_exprs) && rollup_exprs->count() + group_exprs->count() > 0) {
for (int64_t i = 0; OB_SUCC(ret) && i < rollup_exprs->count(); i++) {
if (has_exist_in_array(*group_exprs, rollup_exprs->at(i))){
if (OB_FAIL(group_id_array.push_back(group_exprs->count() + i))) {
LOG_WARN("push_back fail", K(ret));
}
}
}
}
aggr_info.group_idxs_.init(group_id_array.count());
for (int64_t i = 0; OB_SUCC(ret) && i < group_id_array.count(); i++) {
if (OB_FAIL(aggr_info.group_idxs_.push_back(group_id_array.at(i)))) {
LOG_WARN("push_back fail", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (all_param_exprs.empty() && T_FUN_COUNT != raw_expr.get_expr_type() &&
T_FUN_GROUP_ID != raw_expr.get_expr_type()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("only count(*) has empty param", K(ret), "expr_type", raw_expr.get_expr_type());
} else if (OB_FAIL(aggr_info.param_exprs_.assign(all_param_exprs))) {
LOG_WARN("failed to init param_exprs", K(ret));
} else {
LOG_DEBUG("finish fill_aggr_info", K(raw_expr), K(expr), K(aggr_info), K(all_param_exprs));
}
}
}
return ret;
}
int ObStaticEngineCG::extract_non_aggr_expr(ObExpr *input,
const ObRawExpr *raw_input,
common::ObIArray<ObExpr *> &exist_in_child,
common::ObIArray<ObExpr *> &not_exist_in_aggr,
common::ObIArray<ObExpr *> *not_exist_in_groupby,
common::ObIArray<ObExpr *> *not_exist_in_rollup,
common::ObIArray<ObExpr *> *not_exist_in_distinct,
common::ObIArray<ObExpr *> &output) const
{
int ret = common::OB_SUCCESS;
if (OB_FAIL(check_stack_overflow())) {
OB_LOG(WARN, "check_stack_overflow failed", "count", output.count(), K(ret), K(lbt()));
} else if (OB_ISNULL(input)) {
ret = OB_ERR_UNEXPECTED;
OB_LOG(WARN, "input is null", KP(input), K(ret));
} else if (has_exist_in_array(exist_in_child, input)
&& !has_exist_in_array(not_exist_in_aggr, input)
&& (NULL == not_exist_in_groupby || !has_exist_in_array(*not_exist_in_groupby, input))
&& (NULL == not_exist_in_rollup || !has_exist_in_array(*not_exist_in_rollup, input))) {
if (OB_FAIL(add_var_to_array_no_dup(output, input))) {
OB_LOG(WARN, "fail to add_var_to_array_no_dup", "count", output.count(),
KPC(input), K(ret));
}
} else if (NULL != not_exist_in_groupby && has_exist_in_array(*not_exist_in_groupby, input) &&
nullptr != not_exist_in_distinct && has_exist_in_array(*not_exist_in_distinct, input)) {
// select /*+ parallel(3) */ c1,count(c3),sum(distinct c1),min(c2) from t1 order by 1,2,3;
// for three stage, c1 is exists in distinct exprs, then need to calculate the implicit expr
if (OB_FAIL(add_var_to_array_no_dup(output, input))) {
OB_LOG(WARN, "fail to add_var_to_array_no_dup", "count", output.count(),
KPC(input), K(ret));
} else {
LOG_DEBUG("debug add distinct expr", K(*input));
}
} else if (!has_exist_in_array(not_exist_in_aggr, input)) {
for (int64_t i = 0; OB_SUCC(ret) && i < input->arg_cnt_; ++i) {
ObExpr *expr = input->args_[i];
const ObRawExpr *raw_expr = (raw_input != NULL ? raw_input->get_param_expr(i) : NULL);
if (OB_FAIL(extract_non_aggr_expr(expr,
raw_expr,
exist_in_child,
not_exist_in_aggr,
not_exist_in_groupby,
not_exist_in_rollup,
not_exist_in_distinct,
output))) {
OB_LOG(WARN, "fail to extract_non_aggr_expr", "count", output.count(), KPC(expr),
KPC(raw_expr), K(ret));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogLink &op, ObLinkScanSpec &spec, const bool in_root_job)
{
UNUSED(in_root_job);
int ret = OB_SUCCESS;
if (OB_FAIL(op.gen_link_stmt_param_infos())) {
LOG_WARN("failed to generate link stmt", K(ret));
} else if (OB_FAIL(spec.set_param_infos(op.get_param_infos()))) {
LOG_WARN("failed to set param infos", K(ret));
} else if (OB_FAIL(spec.set_stmt_fmt(op.get_stmt_fmt_buf(), op.get_stmt_fmt_len()))) {
LOG_WARN("failed to set stmt fmt", K(ret));
} else {
spec.dblink_id_ = op.get_dblink_id();
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogWindowFunction &op, ObWindowFunctionSpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
int ret = OB_SUCCESS;
ObSEArray<ObExpr*, 16> rd_expr;
ObSEArray<ObExpr*, 16> all_expr;
if (OB_UNLIKELY(op.get_num_of_child() != 1 || OB_ISNULL(op.get_child(0)))) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("wrong number of children", K(ret), K(op.get_num_of_child()));
}
if (OB_SUCC(ret) && op.is_range_dist_parallel()) {
OZ(fill_sort_info(op.get_rd_sort_keys(), spec.rd_sort_collations_, rd_expr));
OZ(fill_sort_funcs(spec.rd_sort_collations_, spec.rd_sort_cmp_funcs_, rd_expr));
OZ(append(all_expr, rd_expr));
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(spec.wf_infos_.prepare_allocate(op.get_window_exprs().count()))) {
LOG_WARN("failed to prepare_allocate the window function.", K(ret));
} else if (OB_FAIL(append_array_no_dup(all_expr, spec.get_child()->output_))) {
LOG_WARN("failed to assign", K(ret));
} else {
spec.single_part_parallel_ = op.is_single_part_parallel();
spec.range_dist_parallel_ = op.is_range_dist_parallel();
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_window_exprs().count(); ++i) {
ObWinFunRawExpr *wf_expr = op.get_window_exprs().at(i);
WinFuncInfo &wf_info = spec.wf_infos_.at(i);
if (OB_ISNULL(wf_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Get unexpected null", K(ret));
} else if (OB_FAIL(fill_wf_info(all_expr, *wf_expr, wf_info))) {
LOG_WARN("failed to generate window function info", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(spec.all_expr_.assign(all_expr))) {
LOG_WARN("failed to assign", K(ret));
}
}
if (OB_SUCC(ret) && op.is_range_dist_parallel()) {
// All function in one window function operator are range distributed currently
OZ(spec.rd_wfs_.init(spec.wf_infos_.count()));
for (int64_t i = 0; OB_SUCC(ret) && i < spec.wf_infos_.count(); i++) {
OZ(spec.rd_wfs_.push_back(i));
OZ(rd_expr.push_back(spec.wf_infos_.at(i).expr_));
}
OZ(spec.rd_coord_exprs_.assign(rd_expr));
spec.rd_pby_sort_cnt_ = op.get_rd_pby_sort_cnt();
}
LOG_DEBUG("finish generate_spec", K(spec), K(ret));
return ret;
}
int ObStaticEngineCG::fill_wf_info(ObIArray<ObExpr *> &all_expr,
ObWinFunRawExpr &win_expr, WinFuncInfo &wf_info)
{
int ret = OB_SUCCESS;
ObRawExpr *agg_raw_expr = win_expr.get_agg_expr();
ObExpr *expr = NULL;
const ObIArray<ObRawExpr *> &func_params = win_expr.get_func_params();
if (OB_FAIL(generate_rt_expr(win_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else if (OB_FAIL(mark_expr_self_produced(&win_expr))) { // win func exprs need to set IS_COLUMNLIZED flag
LOG_WARN("failed to add columnized flag", K(ret));
} else if (OB_FAIL(wf_info.init(func_params.count(),
win_expr.get_partition_exprs().count(),
win_expr.get_order_items().count()))) {
LOG_WARN("failed to init the func info.", K(ret));
} else if (NULL != agg_raw_expr && OB_UNLIKELY(!agg_raw_expr->has_flag(IS_AGG))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expected aggr function", KPC(agg_raw_expr), K(ret));
} else {
if (NULL == agg_raw_expr) {
//do nothing
} else if (OB_FAIL(fill_aggr_info(*static_cast<ObAggFunRawExpr *>(agg_raw_expr),
*expr,
wf_info.aggr_info_, nullptr, nullptr))) {
LOG_WARN("failed to fill_aggr_info", K(ret));
} else {
wf_info.aggr_info_.real_aggr_type_ = agg_raw_expr->get_expr_type();
}
wf_info.expr_ = expr;
wf_info.func_type_ = win_expr.get_func_type();
wf_info.win_type_ = win_expr.get_window_type();
wf_info.is_ignore_null_ = win_expr.is_ignore_null();
wf_info.is_from_first_ = win_expr.is_from_first();
if (OB_SUCC(ret)) {
switch (wf_info.func_type_)
{
case T_FUN_SUM:
case T_FUN_AVG:
case T_FUN_COUNT:
wf_info.remove_type_ = common::REMOVE_STATISTICS;
break;
case T_FUN_MAX:
case T_FUN_MIN:
wf_info.remove_type_ = common::REMOVE_EXTRENUM;
break;
default:
wf_info.remove_type_ = common::REMOVE_INVALID;
break;
}
// ObFloatTC and ObDoubleTC may cause precision question
if (common::REMOVE_STATISTICS == wf_info.remove_type_
&& !wf_info.aggr_info_.param_exprs_.empty()) {
const ObObjTypeClass column_tc =
ob_obj_type_class(wf_info.aggr_info_.get_first_child_type());
if (ObFloatTC == column_tc || ObDoubleTC == column_tc) {
wf_info.remove_type_ = common::REMOVE_INVALID;
}
}
}
wf_info.upper_.is_preceding_ = win_expr.upper_.is_preceding_;
wf_info.upper_.is_unbounded_ = BOUND_UNBOUNDED == win_expr.upper_.type_;
wf_info.upper_.is_nmb_literal_ = win_expr.upper_.is_nmb_literal_;
wf_info.lower_.is_preceding_ = win_expr.lower_.is_preceding_;
wf_info.lower_.is_unbounded_ = BOUND_UNBOUNDED == win_expr.lower_.type_;
wf_info.lower_.is_nmb_literal_ = win_expr.lower_.is_nmb_literal_;
// add window function params.
for (int64_t i = 0; OB_SUCC(ret) && i < func_params.count(); ++i) {
ObRawExpr *raw_expr = func_params.at(i);
expr = NULL;
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("raw expr is null", K(ret), K(i));
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else if (OB_FAIL(wf_info.param_exprs_.push_back(expr))){
LOG_WARN("push back sql expr failed", K(ret));
}
}
if (OB_SUCC(ret)) {
ObRawExpr *raw_expr = win_expr.upper_.interval_expr_;
expr = NULL;
if (NULL == raw_expr) {
//do nothing
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else {
wf_info.upper_.between_value_expr_ = expr;
}
}
if (OB_SUCC(ret)) {
ObRawExpr *raw_expr = win_expr.lower_.interval_expr_;
expr = NULL;
if (NULL == raw_expr) {
//do nothing
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else {
wf_info.lower_.between_value_expr_ = expr;
}
}
if (WINDOW_ROWS == wf_info.win_type_) {
//do nothing
} else {
bool is_asc = win_expr.get_order_items().empty() ? true: win_expr.get_order_items().at(0).is_ascending();
ObRawExpr *upper_raw_expr = (win_expr.upper_.is_preceding_ ^ is_asc)
? win_expr.upper_.exprs_[0] : win_expr.upper_.exprs_[1];
ObRawExpr *lower_raw_expr = (win_expr.lower_.is_preceding_ ^ is_asc)
? win_expr.lower_.exprs_[0] : win_expr.lower_.exprs_[1];
if (OB_SUCC(ret)) {
expr = NULL;
if (NULL == upper_raw_expr) {
//do nothing
} else if (OB_FAIL(generate_rt_expr(*upper_raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else {
wf_info.upper_.range_bound_expr_ = expr;
}
}
if (OB_SUCC(ret)) {
expr = NULL;
if (NULL == lower_raw_expr) {
//do nothing
} else if (OB_FAIL(generate_rt_expr(*lower_raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else {
wf_info.lower_.range_bound_expr_ = expr;
}
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < win_expr.get_partition_exprs().count(); i++) {
const ObRawExpr *raw_expr = win_expr.get_partition_exprs().at(i);
expr = NULL;
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("raw expr is null", K(ret), K(i));
} else if (OB_FAIL(generate_rt_expr(*raw_expr, expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(expr));
} else if (OB_FAIL(wf_info.partition_exprs_.push_back(expr))) {
LOG_WARN("push_back failed", K(ret), K(expr));
}
}
if (OB_SUCC(ret) && !win_expr.get_order_items().empty()) {
if (OB_FAIL(fil_sort_info(win_expr.get_order_items(),
all_expr,
&wf_info.sort_exprs_,
wf_info.sort_collations_,
wf_info.sort_cmp_funcs_))) {
LOG_WARN("failed to fil_sort_info", K(ret));
}
}
LOG_DEBUG("finish fill_wf_info", K(win_expr), K(wf_info), K(ret));
}
return ret;
}
int ObStaticEngineCG::fil_sort_info(const ObIArray<OrderItem> &sort_keys,
ObIArray<ObExpr *> &all_exprs, ObIArray<ObExpr *> *sort_exprs,
ObSortCollations &sort_collations, ObSortFuncs &sort_cmp_funcs)
{
int ret = OB_SUCCESS;
if (OB_FAIL(sort_collations.init(sort_keys.count()))) {
LOG_WARN("failed to init collations", K(ret));
} else if (OB_FAIL(sort_cmp_funcs.init(sort_keys.count()))) {
LOG_WARN("failed to init sort_cmp_funcs_", K(ret));
} else {
for (int64_t i = 0; i < sort_keys.count() && OB_SUCC(ret); ++i) {
const OrderItem &order_item = sort_keys.at(i);
ObExpr *expr = nullptr;
int64_t idx = OB_INVALID_INDEX;
if (OB_FAIL(generate_rt_expr(*order_item.expr_, expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else if (sort_exprs != NULL && OB_FAIL(sort_exprs->push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
} else if (has_exist_in_array(all_exprs, expr, &idx)) {
if (OB_UNLIKELY(idx < 0)
|| OB_UNLIKELY(idx >= all_exprs.count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sort expr not in all expr", K(ret), KPC(expr), K(all_exprs), KP(idx));
}
} else {
if (OB_FAIL(all_exprs.push_back(expr))) {
LOG_WARN("failed to push back expr", K(ret));
} else {
idx = all_exprs.count() - 1;
}
}
if (OB_SUCC(ret)) {
ObSortFieldCollation field_collation(idx,
expr->datum_meta_.cs_type_,
order_item.is_ascending(),
(order_item.is_null_first() ^ order_item.is_ascending()) ? NULL_LAST : NULL_FIRST);
ObSortCmpFunc cmp_func;
cmp_func.cmp_func_ = ObDatumFuncs::get_nullsafe_cmp_func(expr->datum_meta_.type_,
expr->datum_meta_.type_,
field_collation.null_pos_,
field_collation.cs_type_,
lib::is_oracle_mode());
if (OB_ISNULL(cmp_func.cmp_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp_func is null, check datatype is valid", K(ret));
} else if (OB_FAIL(sort_collations.push_back(field_collation))) {
LOG_WARN("failed to push back field collation", K(ret));
} else if (OB_FAIL(sort_cmp_funcs.push_back(cmp_func))) {
LOG_WARN("failed to push back sort function", K(ret));
} else {
LOG_DEBUG("succ to push back field collation", K(field_collation), K(i), K(order_item));
}
}
}
}
return ret;
}
int ObStaticEngineCG::get_pdml_partition_id_column_idx(const ObIArray<ObExpr *> &dml_exprs,
int64_t &idx)
{
int ret = OB_SUCCESS;
bool found = false;
for (int64_t i = 0; i < dml_exprs.count(); i++) {
const ObExpr *expr = dml_exprs.at(i);
if (T_PDML_PARTITION_ID == expr->type_) {
idx = i;
found = true;
break;
}
}
if (!found) {
idx = NO_PARTITION_ID_FLAG; // NO_PARTITION_ID_FLAG = -2
}
return ret;
}
int ObStaticEngineCG::generate_top_fre_hist_expr_operator(ObAggFunRawExpr &raw_expr,
ObAggrInfo &aggr_info)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(T_FUN_TOP_FRE_HIST != raw_expr.get_expr_type() ||
raw_expr.get_param_count() != 3)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid argument", K(raw_expr), K(ret));
} else {
ObRawExpr *win_raw_expr = raw_expr.get_param_expr(0);
ObRawExpr *param_raw_expr = raw_expr.get_param_expr(1);
ObRawExpr *item_raw_expr = raw_expr.get_param_expr(2);
ObExpr *win_expr = NULL;
ObExpr *item_expr = NULL;
raw_expr.get_real_param_exprs_for_update().reset();
if (OB_ISNULL(win_raw_expr) || OB_ISNULL(param_raw_expr) || OB_ISNULL(item_raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(win_raw_expr), K(param_raw_expr), K(item_raw_expr), K(ret));
} else if (OB_FAIL(generate_rt_expr(*win_raw_expr, win_expr)) ||
OB_FAIL(generate_rt_expr(*item_raw_expr, item_expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret), K(*win_raw_expr), K(*item_raw_expr));
} else if (OB_ISNULL(win_expr) || OB_ISNULL(item_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(win_expr), K(item_expr));
} else if (OB_UNLIKELY(!win_expr->obj_meta_.is_numeric_type() ||
!item_expr->obj_meta_.is_numeric_type())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("expr node is null", K(ret), K(win_expr->obj_meta_), K(item_expr->obj_meta_));
} else {
aggr_info.window_size_param_expr_ = win_expr;
aggr_info.item_size_param_expr_ = item_expr;
aggr_info.is_need_deserialize_row_ = raw_expr.is_need_deserialize_row();
if (OB_FAIL(raw_expr.add_real_param_expr(param_raw_expr))) {
LOG_WARN("fail to add param expr to agg expr", K(ret));
} else {/*do nothing*/}
}
}
return ret;
}
int ObStaticEngineCG::generate_hybrid_hist_expr_operator(ObAggFunRawExpr &raw_expr,
ObAggrInfo &aggr_info)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(T_FUN_HYBRID_HIST != raw_expr.get_expr_type() ||
raw_expr.get_param_count() != 3)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get invalid argument", K(raw_expr), K(ret));
} else {
ObRawExpr *param_raw_expr = raw_expr.get_param_expr(0);
ObRawExpr *bucket_num_raw_expr = raw_expr.get_param_expr(1);
ObExpr *bucket_num_expr = NULL;
raw_expr.get_real_param_exprs_for_update().reset();
if ( OB_ISNULL(param_raw_expr) || OB_ISNULL(bucket_num_raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(param_raw_expr), K(bucket_num_raw_expr), K(ret));
} else if (OB_FAIL(generate_rt_expr(*bucket_num_raw_expr, bucket_num_expr))) {
LOG_WARN("failed to generate_rt_expr", K(ret), K(*bucket_num_raw_expr));
} else if (OB_ISNULL(bucket_num_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is null ", K(ret), K(bucket_num_expr));
} else if (OB_UNLIKELY(!bucket_num_expr->obj_meta_.is_numeric_type())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("expr node is null", K(ret), K(bucket_num_expr->obj_meta_));
} else {
aggr_info.bucket_num_param_expr_ = bucket_num_expr;
if (OB_FAIL(raw_expr.add_real_param_expr(param_raw_expr))) {
LOG_WARN("fail to add param expr to agg expr", K(ret));
} else {/*do nothing*/}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogSelectInto &op, ObSelectIntoSpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
ObIAllocator &alloc = phy_plan_->get_allocator();
int ret = OB_SUCCESS;
if (OB_UNLIKELY(1 != op.get_num_of_child())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected count of children", K(ret), K(op.get_num_of_child()));
} else if (OB_FAIL(deep_copy_obj(alloc, op.get_outfile_name(), spec.outfile_name_))) {
LOG_WARN("fail to set outfile name", K(op.get_outfile_name()), K(ret));
} else if (OB_FAIL(deep_copy_obj(alloc, op.get_filed_str(), spec.filed_str_))) {
LOG_WARN("fail to set filed str", K(op.get_filed_str()), K(ret));
} else if (OB_FAIL(deep_copy_obj(alloc, op.get_line_str(), spec.line_str_))) {
LOG_WARN("fail to set line str", K(op.get_line_str()), K(ret));
} else if (OB_FAIL(spec.user_vars_.init(op.get_user_vars().count()))) {
LOG_WARN("init fixed array failed", K(ret), K(op.get_user_vars().count()));
} else {
ObString var;
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_user_vars().count(); ++i) {
var.reset();
if (OB_FAIL(ob_write_string(alloc, op.get_user_vars().at(i), var))) {
LOG_WARN("fail to deep copy string", K(op.get_user_vars().at(i)), K(ret));
} else if (OB_FAIL(spec.user_vars_.push_back(var))) {
LOG_WARN("fail to push back var", K(var), K(ret));
}
}
if (OB_SUCC(ret)) {
spec.into_type_ = op.get_into_type();
spec.closed_cht_ = op.get_closed_cht();
spec.is_optional_ = op.get_is_optional();
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogFunctionTable &op, ObFunctionTableSpec &spec,
const bool in_root_job)
{
UNUSED(in_root_job);
ObIAllocator &alloc = phy_plan_->get_allocator();
ObRawExpr *value_raw_expr = nullptr;
ObExpr *value_expr = nullptr;
int ret = OB_SUCCESS;
if (OB_ISNULL(op.get_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to get stmt", K(ret));
} else if (OB_FAIL(spec.column_exprs_.init(op.get_stmt()->get_column_size()))) {
LOG_WARN("failed to init array", K(ret));
} else if (OB_UNLIKELY(op.get_num_of_child() > 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected count of children", K(ret), K(op.get_num_of_child()));
} else if (OB_ISNULL(value_raw_expr = op.get_value_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to get value raw expr", K(ret));
} else if (OB_FAIL(generate_rt_expr(*value_raw_expr, value_expr))) {
LOG_WARN("failed to generate rt expr", K(ret));
} else {
spec.has_correlated_expr_ = value_raw_expr->has_flag(CNT_DYNAMIC_PARAM);
spec.value_expr_ = value_expr;
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_output_exprs().count(); ++i) {
if (OB_FAIL(mark_expr_self_produced(op.get_output_exprs().at(i)))) {
LOG_WARN("failed to mark expr self produced", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_stmt()->get_column_size(); ++i) {
ObExpr *rt_expr = nullptr;
const ColumnItem *col_item = op.get_stmt()->get_column_item(i);
CK (OB_NOT_NULL(col_item));
CK (OB_NOT_NULL(col_item->expr_));
if (OB_SUCC(ret)
&& col_item->table_id_ == op.get_table_id()
&& col_item->expr_->is_explicited_reference()) {
OZ (mark_expr_self_produced(col_item->expr_));
OZ (generate_rt_expr(*col_item->expr_, rt_expr));
OZ (spec.column_exprs_.push_back(rt_expr));
}
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogInsertAll &op,
ObTableInsertAllSpec &spec,
const bool in_root_job)
{
int ret = OB_SUCCESS;
UNUSED(in_root_job);
if (OB_FAIL(generate_insert_all_with_das(op, spec))) {
LOG_WARN("generate insert all with das failed", K(ret));
} else {
spec.is_insert_all_with_conditions_ = op.is_multi_conditions_insert();
spec.is_insert_all_first_ = op.is_multi_insert_first();
}
return ret;
}
int ObStaticEngineCG::generate_insert_all_with_das(ObLogInsertAll &op, ObTableInsertAllSpec &spec)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(op.get_insert_all_table_info()) ||
OB_ISNULL(phy_plan_) ||
OB_UNLIKELY(op.get_table_list().count() != op.get_insert_all_table_info()->count())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpeceted error", K(ret), K(phy_plan_), K(op.get_insert_all_table_info()));
} else if (OB_FAIL(spec.ins_ctdefs_.allocate_array(phy_plan_->get_allocator(),
op.get_table_list().count()))) {
LOG_WARN("allocate insert ctdef array failed", K(ret));
} else {
spec.plan_->need_drive_dml_query_ = true;
spec.use_dist_das_ = op.is_multi_part_dml();
spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_;
//no need, insert all don't occur returning or instead of trigger
//spec.is_returning_ = op.is_returning();
//spec.has_instead_of_trigger_ = op.has_instead_of_trigger();
spec.insert_table_infos_.set_capacity(op.get_table_list().count());
for (int64_t i = 0; OB_SUCC(ret) && i < op.get_table_list().count(); ++i) {
InsertAllTableInfo *tbl_info = NULL;
const ObInsertAllTableInfo* insert_tbl_info = op.get_insert_all_table_info()->at(i);
const uint64_t loc_table_id = op.get_table_list().at(i);
ObSEArray<IndexDMLInfo *, 4> index_dml_infos;
const IndexDMLInfo *primary_dml_info = NULL;
if (OB_ISNULL(insert_tbl_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get null insert all table info", K(ret));
} else if (OB_ISNULL(primary_dml_info = op.get_primary_dml_info(loc_table_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("primary dml info is null", K(ret), K(loc_table_id));
} else if (OB_FAIL(op.get_index_dml_infos(loc_table_id, index_dml_infos))) {
LOG_WARN("failed to get index dml infos", K(ret));
} else if (OB_FAIL(spec.ins_ctdefs_.at(i).allocate_array(phy_plan_->get_allocator(),
index_dml_infos.count()))) {
LOG_WARN("allocate insert ctdef array failed", K(ret), K(index_dml_infos.count()));
}
for (int64_t j = 0; OB_SUCC(ret) && j < index_dml_infos.count(); ++j) {
const IndexDMLInfo *index_dml_info = index_dml_infos.at(j);
ObInsCtDef *ins_ctdef = nullptr;
if (OB_ISNULL(index_dml_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index dml info", K(ret));
} else if (OB_FAIL(dml_cg_service_.generate_insert_ctdef(op, *index_dml_info, ins_ctdef))) {
LOG_WARN("generate insert ctdef failed", K(ret));
} else {
spec.ins_ctdefs_.at(i).at(j) = ins_ctdef;
}
}
if (OB_SUCC(ret)) {
// if (OB_FAIL(spec.index_dml_count_array_.push_back(spec.ins_ctdefs_.count()))) {
// LOG_WARN("failed to push back", K(ret));
if (OB_FAIL(generate_insert_all_table_info(*insert_tbl_info, tbl_info))) {
LOG_WARN("failed to generate insert all table info", K(ret));
} else if (OB_FAIL(spec.insert_table_infos_.push_back(tbl_info))) {
LOG_WARN("failed to push back", K(ret));
}
}
}
}
return ret;
}
int ObStaticEngineCG::generate_insert_all_table_info(const ObInsertAllTableInfo &insert_tbl_info,
InsertAllTableInfo *&tbl_info)
{
int ret = OB_SUCCESS;
void *ptr = NULL;
tbl_info = NULL;
if (OB_ISNULL(phy_plan_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(phy_plan_));
} else if (OB_ISNULL(ptr = (phy_plan_->get_allocator().alloc(sizeof(InsertAllTableInfo))))) {
ret = common::OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("fail to alloc memory", K(ret), K(ptr));
} else {
tbl_info = new(ptr)InsertAllTableInfo(phy_plan_->get_allocator());
tbl_info->match_conds_idx_ = insert_tbl_info.when_cond_idx_;
if (insert_tbl_info.when_cond_exprs_.empty()) {
/*do nothing*/
} else if (OB_FAIL(generate_rt_exprs(insert_tbl_info.when_cond_exprs_,
tbl_info->match_conds_exprs_))) {
LOG_WARN("fail to generate rt exprs", K(ret), K(insert_tbl_info.when_cond_exprs_));
} else {
LOG_TRACE("Succeed to generate insert all table info", K(insert_tbl_info), K(*tbl_info));
}
}
return ret;
}
int ObStaticEngineCG::generate_spec(ObLogStatCollector &op,
ObStatCollectorSpec &spec, const bool in_root_job)
{
int ret = OB_SUCCESS;
spec.type_ = op.get_stat_collector_type();
spec.is_none_partition_ = op.get_is_none_partition();
if (ObStatCollectorType::SAMPLE_SORT == spec.type_) {
ObIArray<OrderItem> &new_sort_keys = op.get_sort_keys();
if (OB_FAIL(spec.sort_exprs_.init(new_sort_keys.count()))) {
LOG_WARN("failed to init all exprs", K(ret));
} else if (OB_FAIL(fill_sort_info(new_sort_keys,
spec.sort_collations_, spec.sort_exprs_))) {
LOG_WARN("failed to sort info", K(ret));
} else if (OB_FAIL(fill_sort_funcs(spec.sort_collations_,
spec.sort_cmp_funs_, spec.sort_exprs_))) {
LOG_WARN("failed to sort funcs", K(ret));
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpcted type", K(spec.type_));
}
return ret;
}
int ObStaticEngineCG::set_other_properties(const ObLogPlan &log_plan, ObPhysicalPlan &phy_plan)
{
int ret = OB_SUCCESS;
// set params info for plan cache
ObSchemaGetterGuard *schema_guard = log_plan.get_optimizer_context().get_schema_guard();
ObSQLSessionInfo *my_session = log_plan.get_optimizer_context().get_session_info();
ObExecContext *exec_ctx = log_plan.get_optimizer_context().get_exec_ctx();
ObSqlCtx *sql_ctx;
ObPhysicalPlanCtx *plan_ctx = nullptr;
if (OB_ISNULL(exec_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid exec_ctx_", K(ret));
} else if (OB_ISNULL(log_plan.get_stmt()) || OB_ISNULL(schema_guard) || OB_ISNULL(my_session)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt or schema guard is null", K(log_plan.get_stmt()),
K(schema_guard), K(my_session), K(ret));
} else if(OB_ISNULL(sql_ctx = exec_ctx->get_sql_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid sql_ctx", K(ret));
} else if (OB_ISNULL(plan_ctx = exec_ctx->get_physical_plan_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("plan context is null");
} else if (OB_ISNULL(exec_ctx->get_stmt_factory())
|| OB_ISNULL(exec_ctx->get_stmt_factory()->get_query_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid query_ctx", K(ret));
} else {
ret = phy_plan.set_params_info(*(log_plan.get_optimizer_context().get_params()));
}
if (OB_SUCC(ret)) {
//set other params
//set user var assignment property
phy_plan.set_contains_assignment(log_plan.get_stmt()->is_contains_assignment());
phy_plan.set_require_local_execution(!log_plan.get_optimizer_context().get_exchange_allocated());
phy_plan.set_plan_type(log_plan.get_optimizer_context().get_phy_plan_type());
phy_plan.set_location_type(log_plan.get_optimizer_context().get_location_type());
phy_plan.set_param_count(log_plan.get_stmt()->get_pre_param_size());
phy_plan.set_signature(log_plan.get_signature());
phy_plan.set_plan_hash_value(log_plan.get_signature());
phy_plan.set_stmt_type(log_plan.get_stmt()->get_stmt_type());
phy_plan.set_literal_stmt_type(exec_ctx->get_stmt_factory()->get_query_ctx()->get_literal_stmt_type());
if (exec_ctx->get_stmt_factory()->get_query_ctx()->has_nested_sql()) {
phy_plan.set_has_nested_sql(exec_ctx->get_stmt_factory()->get_query_ctx()->has_nested_sql());
}
if (log_plan.get_stmt()->is_insert_stmt() || log_plan.get_stmt()->is_merge_stmt()) {
phy_plan.set_autoinc_params(log_plan.get_stmt()->get_autoinc_params());
}
phy_plan.set_affected_last_insert_id(log_plan.get_stmt()->get_affected_last_insert_id());
phy_plan.set_is_contain_virtual_table(log_plan.get_stmt()->get_query_ctx()->is_contain_virtual_table_);
phy_plan.set_is_contain_inner_table(log_plan.get_stmt()->get_query_ctx()->is_contain_inner_table_);
phy_plan.set_is_affect_found_row(log_plan.get_stmt()->is_affect_found_rows());
phy_plan.set_has_top_limit(log_plan.get_stmt()->has_top_limit());
phy_plan.set_use_px(true);
phy_plan.set_px_dop(log_plan.get_optimizer_context().get_parallel());
phy_plan.set_expected_worker_count(log_plan.get_optimizer_context().get_expected_worker_count());
phy_plan.set_minimal_worker_count(log_plan.get_optimizer_context().get_minimal_worker_count());
phy_plan.set_is_batched_multi_stmt(log_plan.get_optimizer_context().is_batched_multi_stmt());
phy_plan.set_need_consistent_snapshot(log_plan.need_consistent_read());
if (OB_FAIL(phy_plan.set_expected_worker_map(log_plan.get_optimizer_context().get_expected_worker_map()))) {
LOG_WARN("set expected worker map", K(ret));
} else if (OB_FAIL(phy_plan.set_minimal_worker_map(log_plan.get_optimizer_context().get_minimal_worker_map()))) {
LOG_WARN("set minimal worker map", K(ret));
} else {
if (log_plan.get_optimizer_context().is_online_ddl()) {
if (log_plan.get_stmt()->get_table_items().count() > 0) {
const TableItem *insert_table_item = log_plan.get_stmt()->get_table_item(0);
if (nullptr != insert_table_item) {
int64_t ddl_execution_id = 0;
int64_t ddl_task_id = 0;
const ObOptParamHint *opt_params = &log_plan.get_stmt()->get_query_ctx()->get_global_hint().opt_params_;
OZ(opt_params->get_integer_opt_param(ObOptParamHint::DDL_EXECUTION_ID, ddl_execution_id));
OZ(opt_params->get_integer_opt_param(ObOptParamHint::DDL_TASK_ID, ddl_task_id));
phy_plan.set_ddl_schema_version(insert_table_item->ddl_schema_version_);
phy_plan.set_ddl_table_id(insert_table_item->ddl_table_id_);
phy_plan.set_ddl_execution_id(ddl_execution_id);
phy_plan.set_ddl_task_id(ddl_task_id);
}
}
}
}
ObParamOption param_opt = log_plan.get_optimizer_context().get_global_hint().param_option_;
bool is_exact_mode = my_session->get_enable_exact_mode();
if (param_opt == ObParamOption::NOT_SPECIFIED) {
phy_plan.set_need_param(!is_exact_mode);
} else {
phy_plan.set_need_param(param_opt==ObParamOption::FORCE);
}
}
if (OB_SUCC(ret)) {
bool enable = false;
if (OB_FAIL(log_plan.check_enable_plan_expiration(enable))) {
LOG_WARN("failed to check enable plan expiration", K(ret));
} else if (enable) {
phy_plan.set_enable_plan_expiration(true);
}
}
// set schema version and all base table version in phy plan
if (OB_SUCC(ret)) {
const ObIArray<ObSchemaObjVersion> *dependency_table = log_plan.get_stmt()->get_global_dependency_table();
if (OB_ISNULL(dependency_table)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else {
bool has_dep_table = false;
for (int64_t i = 0; OB_SUCC(ret) && !has_dep_table && i < dependency_table->count(); i++) {
if (DEPENDENCY_TABLE == dependency_table->at(i).object_type_) {
has_dep_table = true;
}
}
LOG_DEBUG("is contain global index or dep base table", K(has_dep_table));
phy_plan.set_is_dep_base_table(has_dep_table);
for (int64_t i = 0; OB_SUCC(ret) && i < dependency_table->count(); i++) {
if (DEPENDENCY_TABLE == dependency_table->at(i).object_type_) {
const ObTableSchema *table_schema = NULL;
if (OB_FAIL(schema_guard->get_table_schema(
MTL_ID(),
dependency_table->at(i).get_object_id(),
table_schema))) {
LOG_WARN("fail to get table schema", K(ret), "table_id", dependency_table->at(i).get_object_id());
} else if (OB_ISNULL(table_schema)) {
ret = OB_TABLE_NOT_EXIST;
LOG_WARN("fail to get table schema", K(ret), "table_id", dependency_table->at(i).get_object_id());
} else {
if (table_schema->is_oracle_trx_tmp_table()) {
phy_plan.set_contain_oracle_trx_level_temporary_table();
}
if (table_schema->is_oracle_sess_tmp_table()) {
phy_plan.set_contain_oracle_session_level_temporary_table();
}
LOG_DEBUG("plan contain temporary table",
"trx level", table_schema->is_oracle_trx_tmp_table(),
"session level", table_schema->is_oracle_sess_tmp_table());
}
}
}
}
if (OB_SUCC(ret)) {
int64_t tenant_schema_version = OB_INVALID_VERSION;
int64_t sys_schema_version = OB_INVALID_VERSION;
if (OB_FAIL(phy_plan.get_dependency_table().assign(*dependency_table))) {
LOG_WARN("init dependency table store failed", K(ret));
} else if (OB_FAIL(schema_guard->get_schema_version(my_session->get_effective_tenant_id(),
tenant_schema_version))) {
LOG_WARN("fail to get schema version", K(ret), K(tenant_schema_version));
} else if (OB_FAIL(schema_guard->get_schema_version(OB_SYS_TENANT_ID,
sys_schema_version))) {
LOG_WARN("fail to get schema version", K(ret), K(tenant_schema_version));
} else {
phy_plan.set_tenant_schema_version(tenant_schema_version);
phy_plan.set_sys_schema_version(sys_schema_version);
plan_ctx->set_tenant_schema_version(tenant_schema_version);
}
}
}
//set user and system variables
if (OB_SUCC(ret)) {
ret = phy_plan.set_vars(log_plan.get_stmt()->get_query_ctx()->variables_);
}
if (OB_SUCC(ret)) {
//convert insert row param index map
stmt::StmtType stmt_type = stmt::T_NONE;
if (OB_FAIL(log_plan.get_stmt_type(stmt_type))) {
LOG_WARN("get stmt type of log plan failed", K(ret));
} else if (IS_INSERT_OR_REPLACE_STMT(stmt_type)) {
const ObInsertStmt *insert_stmt = static_cast<const ObInsertStmt *>(log_plan.get_stmt());
if (OB_ISNULL(insert_stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(insert_stmt));
} else if (ObPhyPlanType::OB_PHY_PLAN_DISTRIBUTED == phy_plan.get_plan_type() &&
!insert_stmt->value_from_select() &&
!insert_stmt->has_global_index()) {
RowParamMap row_params;
if (OB_FAIL(map_value_param_index(insert_stmt, row_params))) {
LOG_WARN("failed to map value param index", K(ret));
} else {
PhyRowParamMap &phy_row_params = phy_plan.get_row_param_map();
if (OB_FAIL(phy_row_params.prepare_allocate(row_params.count()))) {
LOG_WARN("prepare allocate physical row param map failed", K(ret), K(row_params.count()));
}
for (int64_t i = 0; OB_SUCC(ret) && i < row_params.count(); ++i) {
phy_row_params.at(i).set_allocator(&phy_plan.get_allocator());
if (OB_FAIL(phy_row_params.at(i).init(row_params.at(i).count()))) {
LOG_WARN("init physical row param map failed", K(ret), K(i));
} else if (OB_FAIL(phy_row_params.at(i).assign(row_params.at(i)))) {
LOG_WARN("assign row param array failed", K(ret), K(i));
}
}
}
}
}
}
//set outline data
if (OB_SUCC(ret)) {
char *buf = NULL;
int64_t pos = 0;
if (NULL == (buf = static_cast<char *>(log_plan.get_allocator()
.alloc(OB_MAX_SQL_LENGTH)))) {
LOG_WARN("sql arena allocator alloc failed", K(ret));
} else if (OB_FAIL(log_plan.print_outline_oneline(buf,
OB_MAX_SQL_LENGTH,
pos))) {
if (OB_SIZE_OVERFLOW == ret) {
ret = OB_SUCCESS;
LOG_WARN("outline data size over flow");
} else {
LOG_WARN("fail to print outline data", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ob_write_string(phy_plan_->get_allocator(),
ObString(pos, buf),
phy_plan_->stat_.outline_data_))) {
LOG_WARN("fail to deep copy outline data", K(ret));
}
}
// set hints info
if (OB_SUCC(ret)) {
char *buf = NULL;
int64_t pos = 0;
if (NULL == (buf = static_cast<char *>(log_plan.get_allocator()
.alloc(OB_MAX_SQL_LENGTH)))) {
LOG_WARN("sql arena allocator alloc failed", K(ret));
} else {
planText plan(buf, OB_MAX_SQL_LENGTH, EXPLAIN_OUTLINE);
plan.is_oneline_ = true;
plan.outline_type_ = USED_HINT;
if (OB_FAIL(log_plan.print_outline(plan, true))) {
if (OB_SIZE_OVERFLOW == ret) {
ret = OB_SUCCESS;
LOG_WARN("hints info size over flow");
} else {
LOG_WARN("fail to print outline", K(ret));
}
}
if (OB_SUCC(ret)) {
pos = plan.pos;
if(OB_FAIL(ob_write_string(phy_plan_->get_allocator(),
ObString(pos, buf),
phy_plan_->stat_.hints_info_))) {
LOG_WARN("fail to deep copy outline data", K(ret));
} else {
// do not check is_hints_all_worked, set false
phy_plan_->stat_.hints_all_worked_ = false;
}
}
}
}
//resolve the first array index of array binding, and store in physical plan
if (OB_SUCC(ret)
&& OB_NOT_NULL(my_session->get_pl_implicit_cursor())
&& my_session->get_pl_implicit_cursor()->get_in_forall() // 仅在FORALL语境中才需要走Array Binding优化
&& (!log_plan.get_optimizer_context().is_batched_multi_stmt())) {
//batch multi stmt使用了param store的array参数,但是它不是一个array binding优化,因此,这里需要排除掉
bool is_found = false;
const ParamStore &param_store = plan_ctx->get_param_store();
for (int64_t i = 0; OB_SUCC(ret) && !is_found && i < param_store.count(); ++i) {
if (param_store.at(i).is_ext()) {
phy_plan.set_first_array_index(i);
is_found = true;
}
}
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(log_plan.get_stmt())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (log_plan.get_stmt()->get_query_ctx()->has_pl_udf_) {
if (log_plan.get_stmt()->is_insert_stmt() ||
log_plan.get_stmt()->is_update_stmt() ||
log_plan.get_stmt()->is_delete_stmt() ||
log_plan.get_stmt()->is_merge_stmt()) {
//为了支持触发器/UDF支持异常捕获,要求含有pl udf的涉及修改表数据的dml串行执行
phy_plan_->set_need_serial_exec(true);
}
phy_plan_->set_contain_pl_udf_or_trigger(true);
phy_plan_->set_has_nested_sql(true);
} else {/*do nothing*/}
}
if (OB_SUCC(ret)) {
phy_plan_->calc_whether_need_trans();
}
return ret;
}
// FIXME bin.lb: We should split the big switch case into logical operator class.
int ObStaticEngineCG::get_phy_op_type(ObLogicalOperator &log_op,
ObPhyOperatorType &type,
const bool in_root_job)
{
int ret = OB_SUCCESS;
type = PHY_INVALID;
switch(log_op.get_type()) {
case log_op_def::LOG_LIMIT: {
type = PHY_LIMIT;
break;
}
case log_op_def::LOG_GROUP_BY: {
auto &op = static_cast<ObLogGroupBy&>(log_op);
switch (op.get_algo()) {
case MERGE_AGGREGATE:
type = PHY_MERGE_GROUP_BY;
break;
case HASH_AGGREGATE:
type = PHY_HASH_GROUP_BY;
break;
case SCALAR_AGGREGATE:
type = PHY_SCALAR_AGGREGATE;
break;
default:
break;
}
break;
}
case log_op_def::LOG_SORT: {
type = PHY_SORT;
break;
}
case log_op_def::LOG_TABLE_SCAN: {
auto &op = static_cast<ObLogTableScan&>(log_op);
if (op.get_contains_fake_cte()) {
type = PHY_FAKE_CTE_TABLE;
} else if (op.is_sample_scan()) {
if (op.get_sample_info().method_ == SampleInfo::ROW_SAMPLE) {
type = PHY_ROW_SAMPLE_SCAN;
} else if (op.get_sample_info().method_ == SampleInfo::BLOCK_SAMPLE){
type = PHY_BLOCK_SAMPLE_SCAN;
}
} else if (op.get_is_multi_part_table_scan()) {
type = PHY_MULTI_PART_TABLE_SCAN;
} else {
type = PHY_TABLE_SCAN;
}
break;
}
case log_op_def::LOG_JOIN: {
auto &op = static_cast<ObLogJoin&>(log_op);
switch(op.get_join_algo()) {
case NESTED_LOOP_JOIN: {
type = CONNECT_BY_JOIN != op.get_join_type()
? PHY_NESTED_LOOP_JOIN
: (GET_MIN_CLUSTER_VERSION() <= CLUSTER_VERSION_2250
? PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX
: (op.get_nl_params().count() > 0
? PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX
: PHY_NESTED_LOOP_CONNECT_BY));
break;
}
case MERGE_JOIN: {
type = PHY_MERGE_JOIN;
break;
}
case HASH_JOIN: {
type = PHY_HASH_JOIN;
break;
}
default: {
break;
}
}
break;
}
case log_op_def::LOG_JOIN_FILTER: {
type = PHY_JOIN_FILTER;
break;
}
case log_op_def::LOG_EXCHANGE: {
// copy from convert_exchange
auto &op = static_cast<ObLogExchange&>(log_op);
if (op.get_plan()->get_optimizer_context().is_batched_multi_stmt()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("batched stmt plan only support executed with DAS");
LOG_USER_ERROR(OB_NOT_SUPPORTED,
"batched stmt plan only support executed with DAS."
"Please contact next layer support to enable DAS configuration");
} else if (op.is_producer()) {
if (op.get_is_remote()) {
type = PHY_DIRECT_TRANSMIT;
} else if (OB_REPARTITION_NO_REPARTITION != op.get_repartition_type()
&& !op.is_slave_mapping()) {
type = PHY_PX_REPART_TRANSMIT;
} else if (ObPQDistributeMethod::LOCAL != op.get_dist_method()) {
type = PHY_PX_DIST_TRANSMIT;
} else if (op.get_plan()->get_optimizer_context().is_online_ddl() && ObPQDistributeMethod::PARTITION_RANGE == op.get_dist_method()) {
type = PHY_PX_REPART_TRANSMIT;
} else if (OB_REPARTITION_NO_REPARTITION != op.get_repartition_type()
&& !op.is_slave_mapping()) {
type = PHY_PX_REPART_TRANSMIT;
} else if (ObPQDistributeMethod::LOCAL != op.get_dist_method()) {
type = PHY_PX_DIST_TRANSMIT;
} else {
// NOTE: 优化器需要和执行器保持一致,既没有分区、又没有HASH、或其它重分区方式时,就使用All To One
type = PHY_PX_REDUCE_TRANSMIT;
}
} else {
if (op.get_is_remote()) {
type = PHY_DIRECT_RECEIVE;
} else if (in_root_job || op.is_rescanable()) {
if (op.is_task_order()) {
type = PHY_PX_ORDERED_COORD;
} else if (op.is_merge_sort()) {
type = PHY_PX_MERGE_SORT_COORD;
} else {
type = PHY_PX_FIFO_COORD;
}
if (op.is_sort_local_order()) {
// root节点不会出现需要local order的exchange-in
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected plan that has merge sort receive "
"with local order in root job", K(ret));
}
} else if (op.is_merge_sort()) {
type = PHY_PX_MERGE_SORT_RECEIVE;
} else {
type = PHY_PX_FIFO_RECEIVE;
}
}
break;
}
case log_op_def::LOG_DISTINCT: {
auto &op = static_cast<ObLogDistinct&>(log_op);
if (MERGE_AGGREGATE == op.get_algo()) {
type = PHY_MERGE_DISTINCT;
} else if (HASH_AGGREGATE == op.get_algo()) {
type = PHY_HASH_DISTINCT;
}
break;
}
case log_op_def::LOG_DELETE: {
auto &op = static_cast<ObLogDelete&>(log_op);
if (op.is_pdml()) {
type = PHY_PX_MULTI_PART_DELETE;
} else {
type = PHY_DELETE;
}
break;
}
case log_op_def::LOG_UPDATE: {
auto &op = static_cast<ObLogUpdate&>(log_op);
if (op.is_pdml()) {
type = PHY_PX_MULTI_PART_UPDATE;
} else {
type = PHY_UPDATE;
}
break;
}
case log_op_def::LOG_FOR_UPD: {
type = PHY_LOCK;
break;
}
case log_op_def::LOG_INSERT: {
auto &op = static_cast<ObLogInsert&>(log_op);
if (op.is_replace()) {
type = PHY_REPLACE;
} else if (op.get_insert_up()) {
type = PHY_INSERT_ON_DUP;
} else if (op.is_pdml()) {
if (op.get_plan()->get_optimizer_context().get_session_info()->get_ddl_info().is_ddl()) {
type = PHY_PX_MULTI_PART_SSTABLE_INSERT;
} else {
type = PHY_PX_MULTI_PART_INSERT;
}
} else {
type = PHY_INSERT;
}
break;
}
case log_op_def::LOG_INSERT_ALL: {
type = PHY_MULTI_TABLE_INSERT;
break;
}
case log_op_def::LOG_ERR_LOG: {
type = PHY_ERR_LOG;
break;
}
case log_op_def::LOG_MERGE: {
type = PHY_MERGE;
break;
}
case log_op_def::LOG_EXPR_VALUES: {
type = PHY_EXPR_VALUES;
break;
}
case log_op_def::LOG_VALUES: {
type = PHY_VALUES;
break;
}
case log_op_def::LOG_SET: {
auto &op = static_cast<ObLogSet&>(log_op);
switch (op.get_set_op()) {
case ObSelectStmt::UNION:
if (op.is_recursive_union()) {
type = PHY_RECURSIVE_UNION_ALL;
} else {
type = (MERGE_SET == op.get_algo() ? PHY_MERGE_UNION : PHY_HASH_UNION);
}
break;
case ObSelectStmt::INTERSECT:
type = (MERGE_SET == op.get_algo() ? PHY_MERGE_INTERSECT : PHY_HASH_INTERSECT);
break;
case ObSelectStmt::EXCEPT:
type = (MERGE_SET == op.get_algo() ? PHY_MERGE_EXCEPT : PHY_HASH_EXCEPT);
break;
default:
break;
}
break;
}
case log_op_def::LOG_SUBPLAN_FILTER: {
type = PHY_SUBPLAN_FILTER;
break;
}
case log_op_def::LOG_SUBPLAN_SCAN: {
type = PHY_SUBPLAN_SCAN;
break;
}
case log_op_def::LOG_MATERIAL: {
type = PHY_MATERIAL;
break;
}
case log_op_def::LOG_WINDOW_FUNCTION: {
type = PHY_WINDOW_FUNCTION;
break;
}
case log_op_def::LOG_SELECT_INTO: {
type = PHY_SELECT_INTO;
break;
}
case log_op_def::LOG_TOPK: {
type = PHY_TOPK;
break;
}
case log_op_def::LOG_COUNT: {
type = PHY_COUNT;
break;
}
case log_op_def::LOG_GRANULE_ITERATOR: {
type = PHY_GRANULE_ITERATOR;
break;
}
case log_op_def::LOG_TABLE_LOOKUP: {
type = PHY_TABLE_LOOKUP;
break;
}
case log_op_def::LOG_SEQUENCE: {
type = PHY_SEQUENCE;
break;
}
case log_op_def::LOG_FUNCTION_TABLE: {
type = PHY_FUNCTION_TABLE;
break;
}
case log_op_def::LOG_MONITORING_DUMP: {
type = PHY_MONITORING_DUMP;
break;
}
case log_op_def::LOG_TEMP_TABLE_INSERT: {
type = PHY_TEMP_TABLE_INSERT;
break;
}
case log_op_def::LOG_TEMP_TABLE_ACCESS: {
type = PHY_TEMP_TABLE_ACCESS;
break;
}
case log_op_def::LOG_TEMP_TABLE_TRANSFORMATION: {
type = PHY_TEMP_TABLE_TRANSFORMATION;
break;
}
case log_op_def::LOG_UNPIVOT: {
type = PHY_UNPIVOT;
break;
}
case log_op_def::LOG_LINK: {
type = PHY_LINK;
break;
}
case log_op_def::LOG_STAT_COLLECTOR: {
type = PHY_STAT_COLLECTOR;
break;
}
default:
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unknown logical operator", K(log_op.get_type()));
break;
}
return ret;
}
int ObStaticEngineCG::classify_anti_monotone_filter_exprs(const ObIArray<ObRawExpr*> &input_filters,
ObIArray<ObRawExpr*> &non_anti_monotone_filters,
ObIArray<ObRawExpr*> &anti_monotone_filters)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < input_filters.count(); i++) {
ObRawExpr *raw_expr = input_filters.at(i);
if (OB_ISNULL(raw_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (raw_expr->has_flag(CNT_ROWNUM) && !raw_expr->has_flag(CNT_COLUMN) &&
!raw_expr->has_flag(CNT_SUB_QUERY)) {
ret = anti_monotone_filters.push_back(raw_expr);
} else {
ret = non_anti_monotone_filters.push_back(raw_expr);
}
}
return ret;
}
int ObStaticEngineCG::map_value_param_index(const ObInsertStmt *insert_stmt,
RowParamMap &row_params_map)
{
int ret = OB_SUCCESS;
int64_t param_cnt = 0;
ObArray<ObSEArray<int64_t, 1>> params_row_map;
if (OB_ISNULL(insert_stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("insert stmt is null", K(ret));
} else {
param_cnt = insert_stmt->get_question_marks_count();
ObSEArray<int64_t, 1> row_indexs;
if (OB_FAIL(params_row_map.prepare_allocate(param_cnt))) {
LOG_WARN("reserve row params map failed", K(ret), K(param_cnt));
} else if (OB_FAIL(row_indexs.push_back(OB_INVALID_INDEX))) {
LOG_WARN("store row index failed", K(ret));
}
//init to OB_INVALID_INDEX
for (int64_t i = 0; OB_SUCC(ret) && i < params_row_map.count(); ++i) {
if (OB_FAIL(params_row_map.at(i).assign(row_indexs))) {
LOG_WARN("init row params map failed", K(ret), K(i));
}
}
}
if (OB_SUCC(ret)) {
const ObIArray<ObRawExpr *> &insert_values = insert_stmt->get_values_vector();
int64_t insert_column_cnt = insert_stmt->get_values_desc().count();
ObSEArray<int64_t, 1> param_idxs;
for (int64_t i = 0; OB_SUCC(ret) && i < insert_values.count(); ++i) {
param_idxs.reset();
if (OB_FAIL(ObRawExprUtils::extract_param_idxs(insert_values.at(i), param_idxs))) {
LOG_WARN("extract param idxs failed", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < param_idxs.count(); ++j) {
if (OB_UNLIKELY(param_idxs.at(j) < 0) || OB_UNLIKELY(param_idxs.at(j) >= param_cnt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("param idx is invalid", K(param_idxs.at(j)), K(param_cnt));
} else if (params_row_map.at(param_idxs.at(j)).count() == 1 && params_row_map.at(param_idxs.at(j)).at(0) == OB_INVALID_INDEX) {
params_row_map.at(param_idxs.at(j)).at(0) = i / insert_column_cnt;
} else if (OB_FAIL(add_var_to_array_no_dup(params_row_map.at(param_idxs.at(j)), i / insert_column_cnt))) {
LOG_WARN("add index no duplicate failed", K(ret));
}
}
}
}
//根据得到的param->row的map关系,转换得到row->param的映射关系,由于存在共有的param,不单独属于任何一行表达式,所以将index=0作为公共param的槽位
//每一行的param从index=1开始存储
if (OB_SUCC(ret)) {
if (OB_FAIL(row_params_map.prepare_allocate(insert_stmt->get_insert_row_count() + 1))) {
LOG_WARN("prepare allocate row params map failed", K(ret), K(insert_stmt->get_insert_row_count()));
}
for (int64_t i = 0; OB_SUCC(ret) && i < params_row_map.count(); ++i) {
for (int64_t j = 0; OB_SUCC(ret) && j < params_row_map.at(i).count(); ++j) {
if (params_row_map.at(i).at(j) == OB_INVALID_INDEX) {
//公共参数
if (OB_FAIL(row_params_map.at(0).push_back(i))) {
LOG_WARN("add param index to row params map failed", K(ret), K(i), K(j));
}
} else {
//具体行中表达式依赖的param
if (OB_FAIL(row_params_map.at(params_row_map.at(i).at(j) + 1).push_back(i))) {
LOG_WARN("add param index to row params map failed", K(ret), K(i), K(j));
}
}
}
}
}
return ret;
}
int ObStaticEngineCG::add_output_datum_check_flag(ObOpSpec &spec)
{
int ret = OB_SUCCESS;
// whitelist not to check output datum
if (!spec.is_vectorized() ||
IS_PX_TRANSMIT(spec.get_type()) ||
PHY_MATERIAL == spec.get_type()) {
// do nothing
} else if (PHY_TABLE_LOOKUP == spec.get_type()) {
if (OB_ISNULL(spec.get_child(0))) {
LOG_INFO("invalid argument, fails to enable checking", K(ret));
} else if (PHY_TABLE_SCAN == spec.get_child(0)->get_type()) {
// Skip datum ptr checking for table lookup's child.
// As table lookup involves two tables, column ref expr(the index column) may point
// to two chunkdatum store under das remote scan. Both pointers are valid,
// the checker always save index table's chunkdatum ptr and may raise false
// alarm.
spec.get_child(0)->need_check_output_datum_ = false;
} else if (PHY_GRANULE_ITERATOR == spec.get_child(0)->get_type()
&& PHY_TABLE_SCAN == spec.get_child(0)->get_child(0)->get_type()) {
spec.get_child(0)->need_check_output_datum_ = false;
spec.get_child(0)->get_child(0)->need_check_output_datum_ = false;
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid child of table lookup", K(spec.get_child(0)->get_type()
), K(ret));
}
} else if (PHY_UNPIVOT == spec.get_type()) {
if (OB_ISNULL(spec.get_child(0))) {
LOG_INFO("invalid argument, fails to enable checking", K(ret));
} else if (spec.get_child(0)->get_type() != PHY_SUBPLAN_SCAN) {
LOG_INFO("Unexpected type", K(ret), K(spec.get_child(0)->get_type()));
} else {
// Because the Unpivot will affect the output datum of the SubplanScan,
// which is an by designed case, we need to set the SubplanScan operator
// to not check the ouput datum.
spec.get_child(0)->need_check_output_datum_ = false;
}
} else {
spec.need_check_output_datum_ = true;
}
return ret;
}
int ObStaticEngineCG::generate_calc_part_id_expr(const ObRawExpr &src,
const ObDASTableLocMeta *loc_meta,
ObExpr *&dst)
{
int ret = OB_SUCCESS;
if (OB_FAIL(generate_rt_expr(src, dst))) {
LOG_WARN("generate calc part id expr failed", K(ret));
} else if (loc_meta != nullptr && !loc_meta->unuse_related_pruning_) {
//related local index tablet_id pruning only can be used in local plan or remote plan(all operator
//use the same das context),
//because the distributed plan will transfer tablet_id through exchange operator,
//but the related tablet_id map can not be transfered by exchange operator,
//unused related pruning in distributed plan's dml operator,
//we will build the related tablet_id map when dml operator be opened in distributed plan
CalcPartitionBaseInfo *calc_part_info = static_cast<CalcPartitionBaseInfo*>(dst->extra_info_);
if (OB_FAIL(calc_part_info->related_table_ids_.assign(loc_meta->related_table_ids_))) {
LOG_WARN("assign related table ids failed", K(ret));
}
}
return ret;
}
int ObStaticEngineCG::check_only_one_unique_key(const ObLogPlan& log_plan,
const ObTableSchema* table_schema,
bool& only_one_unique_key)
{
int ret = OB_SUCCESS;
ObSchemaGetterGuard *schema_guard = log_plan.get_optimizer_context().get_schema_guard();
ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;
const ObTableSchema *index_schema = NULL;
int64_t unique_index_cnt = 0;
if (OB_ISNULL(schema_guard) || OB_ISNULL(table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(schema_guard), K(table_schema));
} else {
if (!table_schema->is_heap_table()) {
++unique_index_cnt;
}
if (OB_FAIL(table_schema->get_simple_index_infos(simple_index_infos))) {
LOG_WARN("get simple_index_infos failed", K(ret));
} else if (simple_index_infos.count() > 0) {
for (int64_t i = 0; OB_SUCC(ret) && i < simple_index_infos.count(); i++) {
if (OB_FAIL(schema_guard->get_table_schema(MTL_ID(), simple_index_infos.at(i).table_id_, index_schema))) {
LOG_WARN("fail to get table schema", K(ret), "table_id", simple_index_infos.at(i).table_id_);
} else if (OB_ISNULL(index_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get table schema", K(ret), K(index_schema));
} else if (index_schema->is_unique_index() && !index_schema->is_final_invalid_index()) {
++unique_index_cnt;
}
}
}
}
if (OB_SUCC(ret)) {
only_one_unique_key = (1 == unique_index_cnt);
}
return ret;
}
} // end namespace sql
} // end namespace oceanbase