diff --git a/src/objit/include/objit/expr/ob_iraw_expr.h b/src/objit/include/objit/expr/ob_iraw_expr.h index 1507223125..1a666ccd17 100644 --- a/src/objit/include/objit/expr/ob_iraw_expr.h +++ b/src/objit/include/objit/expr/ob_iraw_expr.h @@ -51,6 +51,7 @@ public: EXPR_EXEC_PARAM, EXPR_PL_QUERY_REF, EXPR_MATCH_AGAINST, + EXPR_UNPIVOT, // FARM COMPAT WHITELIST }; typedef ObExprVisitor Visitor; @@ -107,6 +108,7 @@ public: inline bool is_pseudo_column_expr() const { return EXPR_PSEUDO_COLUMN == expr_class_; } inline bool is_alias_ref_expr() const { return EXPR_ALIAS_REF == expr_class_; } inline bool is_match_against_expr() const { return EXPR_MATCH_AGAINST == expr_class_; } + inline bool is_unpivot_expr() const { return EXPR_UNPIVOT == expr_class_; } inline bool is_terminal_expr() const { return is_var_expr() || is_op_pseudo_column_expr() || is_const_or_param_expr() diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index 398146f10f..a972ae394f 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -1430,6 +1430,7 @@ ob_set_subtarget(ob_sql resolver_dml resolver/dml/ob_update_stmt.cpp resolver/dml/ob_view_table_resolver.cpp resolver/dml/ob_inlist_resolver.cpp + resolver/dml/ob_transpose_resolver.cpp ) ob_set_subtarget(ob_sql resolver_expr diff --git a/src/sql/code_generator/ob_expr_generator_impl.cpp b/src/sql/code_generator/ob_expr_generator_impl.cpp index aca99b20e5..2f1657d0b8 100644 --- a/src/sql/code_generator/ob_expr_generator_impl.cpp +++ b/src/sql/code_generator/ob_expr_generator_impl.cpp @@ -505,8 +505,6 @@ int ObExprGeneratorImpl::visit(ObColumnRefRawExpr &expr) } else { // do nothing for infix expr generation, especially processed in infix_visit_child() } - } else if (expr.is_unpivot_mocked_column()) { - //do nothing } else { // 基本列表达式在此之前外部已经完成翻译 ret = OB_ERR_UNEXPECTED; @@ -2043,6 +2041,31 @@ int ObExprGeneratorImpl::visit(ObMatchFunRawExpr &expr) return ret; } +int ObExprGeneratorImpl::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_SUCCESS; + // 不为 unpivot expr 生成 expr operator + ObPostExprItem item; + item.set_accuracy(expr.get_accuracy()); + if (OB_ISNULL(sql_expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("sql_expr_ is NULL"); + } else if (expr.has_flag(IS_COLUMNLIZED)) { + int64_t idx = OB_INVALID_INDEX; + if (OB_FAIL(column_idx_provider_.get_idx(&expr, idx))) { + LOG_WARN("get index failed", K(ret)); + } else if (OB_FAIL(item.set_column(idx))) { + LOG_WARN("failed to set column", K(ret), K(expr)); + } else if (OB_FAIL(sql_expr_->add_expr_item(item, &expr))) { + LOG_WARN("failed to add expr item", K(ret)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("all unpivot expr should have been generated", K(expr), K(&expr)); + } + return ret; +} + bool ObExprGeneratorImpl::skip_child(ObRawExpr &expr) { return expr.has_flag(IS_COLUMNLIZED) || expr.is_query_ref_expr(); diff --git a/src/sql/code_generator/ob_expr_generator_impl.h b/src/sql/code_generator/ob_expr_generator_impl.h index f0617bc859..7affe1ba54 100644 --- a/src/sql/code_generator/ob_expr_generator_impl.h +++ b/src/sql/code_generator/ob_expr_generator_impl.h @@ -98,6 +98,7 @@ private: virtual int visit(ObPseudoColumnRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); virtual bool skip_child(ObRawExpr &expr); private: // types and constants diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index 6ace0504bc..fca9a1c0c6 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -411,10 +411,11 @@ int ObStaticEngineCG::check_expr_columnlized(const ObRawExpr *expr) || (expr->is_column_ref_expr() && is_shadow_column(static_cast(expr)->get_column_id())) || expr->is_var_expr()) { // skip - } else if ((expr->is_aggr_expr() || (expr->is_win_func_expr()) || expr->is_match_against_expr()) + } else if ((expr->is_aggr_expr() || (expr->is_win_func_expr()) + || expr->is_match_against_expr() || expr->is_unpivot_expr()) && !expr->has_flag(IS_COLUMNLIZED)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("aggr, win_func, match_against exprs should be columnlized", K(ret), KPC(expr)); + LOG_WARN("aggr, win_func, match_against and unpivot exprs should be columnlized", K(ret), KPC(expr)); } else if (!expr->has_flag(IS_COLUMNLIZED)) { if (0 == expr->get_param_count()) { ret = OB_ERR_UNEXPECTED; @@ -5034,24 +5035,68 @@ int ObStaticEngineCG::generate_cte_table_spec(ObLogTableScan &op, ObFakeCTETable return ret; } -int ObStaticEngineCG::generate_spec(ObLogUnpivot &op, ObUnpivotSpec &spec, const bool in_root_job) +int ObStaticEngineCG::generate_spec(ObLogUnpivot &op, ObUnpivotSpec&spec, const bool in_root_job) +{ + int ret = OB_NOT_SUPPORTED; + UNUSED(op); + UNUSED(spec); + UNUSED(in_root_job); + LOG_WARN("unpivot is not support on high version machine during updating", K(ret)); + return ret; +} + +int ObStaticEngineCG::generate_spec(ObLogUnpivot &op, ObUnpivotV2Spec &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(); + 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(spec.origin_exprs_.init(op.get_origin_exprs().count())) || + OB_FAIL(spec.label_exprs_.init(op.get_label_exprs().count())) || + OB_FAIL(spec.value_exprs_.init(op.get_value_exprs().count()))) { + LOG_WARN("failed to init ExprFixedArray", K(ret)); + } else { + spec.is_include_null_ = op.is_include_null(); + for (int64_t i = 0; OB_SUCC(ret) && i < op.get_origin_exprs().count(); ++i) { + ObRawExpr *old_expr = op.get_origin_exprs().at(i); + ObExpr *rt_expr = NULL; + if (OB_ISNULL(old_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid old_expr", K(ret)); + } else if (OB_FAIL(generate_rt_expr(*old_expr, rt_expr))) { + LOG_WARN("failed to generate rt expr", K(ret)); + } else if (OB_FAIL(spec.origin_exprs_.push_back(rt_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < op.get_label_exprs().count(); ++i) { + ObRawExpr *label_expr = op.get_label_exprs().at(i); + ObExpr *rt_expr = NULL; + if (OB_ISNULL(label_expr) || OB_UNLIKELY(ObRawExpr::EXPR_UNPIVOT != label_expr->get_expr_class())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid label_expr", K(ret)); + } else if (OB_FAIL(generate_rt_expr(*label_expr, rt_expr))) { + LOG_WARN("failed to generate rt expr", K(ret)); + } else if (OB_FAIL(spec.label_exprs_.push_back(rt_expr))) { + LOG_WARN("failed to push back", K(ret)); + } else if (OB_FAIL(mark_expr_self_produced(label_expr))) { + LOG_WARN("mark expr self produced failed", K(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < op.get_value_exprs().count(); ++i) { + ObRawExpr *val_expr = op.get_value_exprs().at(i); + ObExpr *rt_expr = NULL; + if (OB_ISNULL(val_expr) || OB_UNLIKELY(ObRawExpr::EXPR_UNPIVOT != val_expr->get_expr_class())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid val_expr", K(ret)); + } else if (OB_FAIL(generate_rt_expr(*val_expr, rt_expr))) { + LOG_WARN("failed to generate rt expr", K(ret)); + } else if (OB_FAIL(spec.value_exprs_.push_back(rt_expr))) { + LOG_WARN("failed to push back", K(ret)); + } else if (OB_FAIL(mark_expr_self_produced(val_expr))) { + LOG_WARN("mark expr self produced failed", K(ret)); + } } } return ret; @@ -10055,7 +10100,7 @@ int ObStaticEngineCG::get_phy_op_type(ObLogicalOperator &log_op, break; } case log_op_def::LOG_UNPIVOT: { - type = PHY_UNPIVOT; + type = PHY_UNPIVOT_V2; break; } case log_op_def::LOG_LINK_SCAN: { @@ -10298,6 +10343,7 @@ int ObStaticEngineCG::add_output_datum_check_flag(ObOpSpec &spec) // 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 output datum. + // tuliwei.tlw update: unpivot v2 (PHY_UNPIVOT_V2) do not need this spec.get_child(0)->need_check_output_datum_ = false; } } else { diff --git a/src/sql/code_generator/ob_static_engine_cg.h b/src/sql/code_generator/ob_static_engine_cg.h index 46a8fd31ed..286a7cf4a9 100644 --- a/src/sql/code_generator/ob_static_engine_cg.h +++ b/src/sql/code_generator/ob_static_engine_cg.h @@ -61,6 +61,7 @@ class ObLogTableScan; class ObTableScanSpec; class ObLogUnpivot; class ObUnpivotSpec; +class ObUnpivotV2Spec; class ObFakeCTETableSpec; class ObHashJoinSpec; class ObHashJoinVecSpec; @@ -340,7 +341,8 @@ private: int generate_spec(ObLogTableScan &op, ObTableScanSpec &spec, const bool in_root_job); int generate_spec(ObLogTableScan &op, ObFakeCTETableSpec &spec, const bool in_root_job); - int generate_spec(ObLogUnpivot &op, ObUnpivotSpec &spec, const bool in_root_job); + int generate_spec(ObLogUnpivot &op, ObUnpivotSpec&spec, const bool in_root_job); + int generate_spec(ObLogUnpivot &op, ObUnpivotV2Spec &spec, const bool in_root_job); int generate_spec(ObLogTempTableAccess &op, ObTempTableAccessOpSpec &spec, const bool in_root_job); int generate_spec(ObLogTempTableInsert &op, ObTempTableInsertOpSpec &spec, const bool in_root_job); diff --git a/src/sql/engine/ob_operator_reg.h b/src/sql/engine/ob_operator_reg.h index 9e734184ac..45e5ca9e9e 100644 --- a/src/sql/engine/ob_operator_reg.h +++ b/src/sql/engine/ob_operator_reg.h @@ -496,6 +496,12 @@ class ObUnpivotOp; REGISTER_OPERATOR(ObLogUnpivot, PHY_UNPIVOT, ObUnpivotSpec, ObUnpivotOp, NOINPUT, VECTORIZED_OP); +class ObUnpivotV2Spec; +class ObUnpivotV2Op; +REGISTER_OPERATOR(ObLogUnpivot, PHY_UNPIVOT_V2, ObUnpivotV2Spec, ObUnpivotV2Op, + NOINPUT, VECTORIZED_OP, 0 /*+version*/, SUPPORT_RICH_FORMAT, + "PHY_VEC_UNPIVOT"); + class ObLogForUpdate; class ObTableLockOpInput; class ObTableLockSpec; diff --git a/src/sql/engine/subquery/ob_unpivot_op.cpp b/src/sql/engine/subquery/ob_unpivot_op.cpp index 4303ae9b70..867a8d189f 100644 --- a/src/sql/engine/subquery/ob_unpivot_op.cpp +++ b/src/sql/engine/subquery/ob_unpivot_op.cpp @@ -14,11 +14,19 @@ #include "sql/engine/subquery/ob_unpivot_op.h" #include "sql/engine/ob_exec_context.h" +#include "sql/engine/basic/ob_vector_result_holder.h" namespace oceanbase { namespace sql { +// unpivot v1 +OB_SERIALIZE_MEMBER(ObUnpivotInfo, + old_column_count_, + unpivot_column_count_, + for_column_count_, + is_include_null_); + ObUnpivotSpec::ObUnpivotSpec(ObIAllocator &alloc, const ObPhyOperatorType type) : ObOpSpec(alloc, type), max_part_count_(-1), unpivot_info_(false, 0, 0, 0) {} @@ -288,5 +296,530 @@ void ObUnpivotOp::reset() memset(multiplex_, 0, MY_SPEC.max_batch_size_ * MY_SPEC.get_output_count() * sizeof(ObDatum)); } +// unpivot v2 +ObUnpivotV2Spec::ObUnpivotV2Spec(ObIAllocator &alloc, const ObPhyOperatorType type) + : ObOpSpec(alloc, type), origin_exprs_(alloc), + label_exprs_(alloc), value_exprs_(alloc), is_include_null_(false) {} + +OB_SERIALIZE_MEMBER((ObUnpivotV2Spec, ObOpSpec), origin_exprs_, + label_exprs_, value_exprs_, is_include_null_); + +ObUnpivotV2Op::ObUnpivotV2Op(ObExecContext &exec_ctx, const ObOpSpec &spec, ObOpInput *input) + : ObOperator(exec_ctx, spec, input), cur_part_idx_(-1), offset_(0), + child_brs_(NULL), buffer_(NULL), using_buffer_(false) {} + +int ObUnpivotV2Op::inner_open() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObOperator::inner_open())) { + LOG_WARN("failed to open in base class", K(ret)); + } else if (!MY_SPEC.use_rich_format_) { + int64_t size = MY_SPEC.max_batch_size_ * MY_SPEC.origin_exprs_.count() * sizeof(ObDatum); + buffer_ = static_cast(ctx_.get_allocator().alloc(size)); + if (size > 0 && OB_ISNULL(buffer_)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret), K(size), K(buffer_)); + } + } else { + void *holder_buf = nullptr; + holder_buf = ctx_.get_allocator().alloc(sizeof(ObVectorsResultHolder)); + if (OB_ISNULL(holder_buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret)); + } else { + vec_holder_ = new (holder_buf) ObVectorsResultHolder(); + if (OB_FAIL(vec_holder_->init(child_->get_spec().output_, eval_ctx_))) { + LOG_WARN("init result holder failed", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (MY_SPEC.use_rich_format_) { + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.label_exprs_.count(); ++i) { + ObExpr *label_expr = MY_SPEC.label_exprs_.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < label_expr->arg_cnt_; ++j) { + ObExpr *arg_expr = label_expr->args_[j]; + if (arg_expr->is_batch_result()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param expr of unpivot value expr", K(ret)); + } + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.value_exprs_.count(); ++i) { + ObExpr *value_expr = MY_SPEC.value_exprs_.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < value_expr->arg_cnt_; ++j) { + ObExpr *arg_expr = value_expr->args_[j]; + if (!arg_expr->is_batch_result()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param expr of unpivot value expr", K(ret)); + } + } + } + } + return ret; +} + +int ObUnpivotV2Op::inner_close() +{ + return ObOperator::inner_close(); +} + +int ObUnpivotV2Op::inner_rescan() +{ + reset(); + return ObOperator::inner_rescan(); +} + +int ObUnpivotV2Op::inner_get_next_batch(const int64_t max_row_cnt) +{ + return MY_SPEC.use_rich_format_ ? next_vector(max_row_cnt) : next_batch(max_row_cnt); +} + +int ObUnpivotV2Op::next_vector(const int64_t max_row_cnt) +{ + int ret = OB_SUCCESS; + int64_t batch_size = common::min(max_row_cnt, MY_SPEC.max_batch_size_); + int64_t part_count = MY_SPEC.label_exprs_.at(0)->arg_cnt_; + clear_evaluated_flag(); + if (cur_part_idx_ == -1 || cur_part_idx_ == part_count) { + if (using_buffer_) { + if (OB_FAIL(vec_holder_->restore())) { + LOG_WARN("faild to restore child vector", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(child_->get_next_batch(batch_size, child_brs_))) { + LOG_WARN("failed to get next batch of child", K(ret)); + } else { + cur_part_idx_ = 0; + using_buffer_ = false; + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(brs_.copy(child_brs_))) { + LOG_WARN("failed to copy", K(ret)); + } else if (child_brs_->end_ && child_brs_->size_ == 0) { + // do nothing + } else { + if (offset_ == 0) { + if (batch_size >= child_brs_->size_) { + if (OB_FAIL(project_vector())) { + LOG_WARN("failed to do projection", K(ret)); + } + } else { + brs_.size_ = batch_size; + if (using_buffer_ && OB_FAIL(vec_holder_->restore())) { + LOG_WARN("failed to restore child vector", K(ret)); + } else if (!using_buffer_ && OB_FAIL(vec_holder_->save(child_brs_->size_))) { + LOG_WARN("failed to get result buffer", K(ret)); + } else if (FALSE_IT(using_buffer_ = true)) { + } else if (OB_FAIL(project_vector_with_offset())) { + LOG_WARN("failed to do batch copy", K(ret)); + } + } + } else { + brs_.size_ = common::min(brs_.size_, child_brs_->size_ - offset_); + if (OB_FAIL(vec_holder_->restore())) { + LOG_WARN("failed to restore child vector", K(ret)); + } else { + brs_.set_all_rows_active(true); + for (int64_t i = 0; OB_SUCC(ret) && i < brs_.size_; ++i) { + if (child_brs_->skip_->at(i + offset_)) { + brs_.set_skip(i); + brs_.set_all_rows_active(false); + } else { + brs_.reset_skip(i); + } + } + } + if (OB_FAIL(project_vector_with_offset())) { + LOG_WARN("failed to do batch copy", K(ret)); + } + } + if (!MY_SPEC.is_include_null_) { + for (int64_t i = 0; OB_SUCC(ret) && i < brs_.size_; ++i) { + if (brs_.skip_->at(i)) { + // skip, do nothing + } else { + bool is_all_null = true; + for (int64_t j = 0; OB_SUCC(ret) && is_all_null && j < MY_SPEC.value_exprs_.count(); ++j) { + ObExpr *expr = MY_SPEC.value_exprs_.at(j); + if (!expr->get_vector(eval_ctx_)->is_null(i)) { + is_all_null = false; + } + } + if (OB_SUCC(ret) && is_all_null) { + brs_.skip_->set(i); + brs_.set_all_rows_active(false); + } + } + } + } + brs_.end_ = cur_part_idx_ == part_count && child_brs_->end_; + } + return ret; +} + +int ObUnpivotV2Op::project_vector() +{ + int ret = OB_SUCCESS; + if (using_buffer_) { + if (OB_FAIL(vec_holder_->restore())) { + LOG_WARN("failed to restore child vector", K(ret)); + } else { + using_buffer_ = false; + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.label_exprs_.count(); ++i) { + ObExpr *expr = MY_SPEC.label_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + if (OB_FAIL(arg_expr->eval_vector(eval_ctx_, *child_brs_))) { + LOG_WARN("failed to eval arg expr", K(ret)); + } else if (arg_expr->get_format(eval_ctx_) != VEC_UNIFORM_CONST) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected arg_expr format", K(ret)); + } else { + ObDatum *arg_datum = static_cast(arg_expr->get_vector(eval_ctx_))->get_datums(); + OZ(expr->init_vector(eval_ctx_, VEC_UNIFORM_CONST, child_brs_->size_)); + ObUniformBase *vec = static_cast(expr->get_vector(eval_ctx_)); + *vec->get_datums() = *arg_datum; + } + expr->set_evaluated_projected(eval_ctx_); + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.value_exprs_.count(); ++i) { + ObExpr *expr = MY_SPEC.value_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + if (OB_FAIL(arg_expr->eval_vector(eval_ctx_, *child_brs_))) { + LOG_WARN("eval batch failed", K(ret)); + } else { + VectorHeader &arg_vec_header = arg_expr->get_vector_header(eval_ctx_); + VectorHeader &vec_header = expr->get_vector_header(eval_ctx_); + if (arg_vec_header.format_ == VEC_UNIFORM_CONST) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected arg_expr format", K(ret)); + } else if (arg_vec_header.format_ == VEC_UNIFORM) { + ObUniformBase *uni_vec = static_cast(arg_expr->get_vector(eval_ctx_)); + ObDatum *src = uni_vec->get_datums(); + ObDatum *dst = expr->locate_batch_datums(eval_ctx_); + if (src != dst) { + MEMCPY(dst, src, child_brs_->size_ * sizeof(ObDatum)); + } + OZ(expr->init_vector(eval_ctx_, VEC_UNIFORM, child_brs_->size_)); + } else { + vec_header = arg_vec_header; + if (arg_expr->is_nested_expr()) { + OZ(expr->assign_nested_vector(*arg_expr, eval_ctx_)); + } + } + } + expr->set_evaluated_projected(eval_ctx_); + } + if (OB_SUCC(ret)) { + cur_part_idx_++; + } + return ret; +} + +int ObUnpivotV2Op::project_vector_with_offset() +{ + int ret = OB_SUCCESS; + int64_t pos = 0; + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.origin_exprs_.count(); ++i) { + ObExpr *expr = MY_SPEC.origin_exprs_.at(i); + ObIVector *vec = expr->get_vector(eval_ctx_); + if (0 != offset_) { + for (int64_t j = 0; OB_SUCC(ret) && j < brs_.size_; ++j) { + if (child_brs_->skip_->at(j + offset_)) { + /* do nothing */ + } else if (vec->is_null(j + offset_)) { + vec->set_null(j); + } else { + vec->unset_null(j); + vec->set_payload_shallow(j, vec->get_payload(j + offset_), vec->get_length(j + offset_)); + } + } + } + expr->set_evaluated_projected(eval_ctx_); + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.label_exprs_.count(); ++i) { + ObExpr *expr = MY_SPEC.label_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + if (OB_FAIL(arg_expr->eval_vector(eval_ctx_, *child_brs_))) { + LOG_WARN("failed to eval arg expr", K(ret)); + } else { + ObDatum *arg_datum = static_cast(arg_expr->get_vector(eval_ctx_))->get_datums(); + OZ(expr->init_vector(eval_ctx_, VEC_UNIFORM_CONST, child_brs_->size_)); + ObUniformBase *vec = static_cast(expr->get_vector(eval_ctx_)); + *vec->get_datums() = *arg_datum; + } + expr->set_evaluated_projected(eval_ctx_); + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.value_exprs_.count(); ++ i) { + ObExpr *expr = MY_SPEC.value_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + if (OB_FAIL(arg_expr->eval_vector(eval_ctx_, *child_brs_))) { + LOG_WARN("failed to eval batch for arg expr", K(ret)); + } else if (OB_FAIL(expr->init_vector(eval_ctx_, arg_expr->get_format(eval_ctx_), brs_.size_))) { + LOG_WARN("failed to init vector", K(ret)); + } else { + ObIVector *vec = expr->get_vector(eval_ctx_); + ObIVector *arg_vec = arg_expr->get_vector(eval_ctx_); + for (int64_t j = 0; OB_SUCC(ret) && j < brs_.size_; ++j) { + if (child_brs_->skip_->at(j + offset_)) { + /* do nothing */ + } else if (arg_vec->is_null(j + offset_)) { + vec->set_null(j); + } else { + vec->unset_null(j); + vec->set_payload_shallow(j, arg_vec->get_payload(j + offset_), arg_vec->get_length(j + offset_)); + } + } + expr->set_evaluated_projected(eval_ctx_); + } + } + if (OB_SUCC(ret)) { + offset_ += brs_.size_; + if (offset_ == child_brs_->size_) { + offset_ = 0; + cur_part_idx_++; + } + } + return ret; +} + +int ObUnpivotV2Op::next_batch(const int64_t max_row_cnt) +{ + int ret = OB_SUCCESS; + int64_t batch_size = common::min(max_row_cnt, MY_SPEC.max_batch_size_); + int64_t part_count = MY_SPEC.label_exprs_.at(0)->arg_cnt_; + clear_evaluated_flag(); + if (cur_part_idx_ == -1 || cur_part_idx_ == part_count) { + if (OB_FAIL(restore_batch_if_need())) { + LOG_WARN("failed to restore batch", K(ret)); + } else if (OB_FAIL(child_->get_next_batch(batch_size, child_brs_))) { + LOG_WARN("failed to get next batch of child", K(ret)); + } else { + cur_part_idx_ = 0; + using_buffer_ = false; + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(brs_.copy(child_brs_))) { + LOG_WARN("failed to copy", K(ret)); + } else if (child_brs_->end_ && child_brs_->size_ == 0) { + // do nothing + } else { + if (offset_ == 0) { + if (batch_size >= child_brs_->size_) { + if (OB_FAIL(batch_project_data())) { + LOG_WARN("failed to do projection", K(ret)); + } + } else { + brs_.size_ = batch_size; + if (OB_FAIL(get_result_buffer())) { + LOG_WARN("failed to get result buffer", K(ret)); + } else if (OB_FAIL(batch_copy_data())) { + LOG_WARN("failed to do batch copy", K(ret)); + } + } + } else { + brs_.size_ = common::min(brs_.size_, child_brs_->size_ - offset_); + if (OB_FAIL(batch_copy_data())) { + LOG_WARN("failed to do batch copy", K(ret)); + } + } + if (!MY_SPEC.is_include_null_) { + for (int64_t i = 0; OB_SUCC(ret) && i < brs_.size_; ++i) { + if (brs_.skip_->at(i)) { + // skip, do nothing + } else { + bool is_all_null = true; + for (int64_t j = 0; OB_SUCC(ret) && is_all_null && j < MY_SPEC.value_exprs_.count(); ++j) { + ObExpr *expr = MY_SPEC.value_exprs_.at(j); + if (!expr->locate_batch_datums(eval_ctx_)[i].is_null()) { + is_all_null = false; + } + } + if (OB_SUCC(ret) && is_all_null) { + brs_.skip_->set(i); + brs_.set_all_rows_active(false); + } + } + } + } + brs_.end_ = cur_part_idx_ == part_count && child_brs_->end_; + } + return ret; +} + +// project lab expr and val expr +int ObUnpivotV2Op::batch_project_data() +{ + int ret = OB_SUCCESS; + if (using_buffer_) { + int64_t pos = 0; + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.origin_exprs_.count(); ++ i) { + ObExpr *expr = MY_SPEC.origin_exprs_.at(i); + ObDatum *buffer_datums = buffer_ + pos; + if (expr->is_batch_result()) { + ObDatum *datums = expr->locate_batch_datums(eval_ctx_); + MEMCPY(datums, buffer_datums, child_brs_->size_ * sizeof(ObDatum)); + pos += child_brs_->size_; + } else { + // expr that is not batch result do not need modify datum; + // do nothing + } + expr->set_evaluated_projected(eval_ctx_); + using_buffer_ = false; + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.label_exprs_.count(); ++i) { + ObExpr *expr = MY_SPEC.label_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + ObDatum *datum = NULL; + if (OB_FAIL(arg_expr->eval(eval_ctx_, datum))) { + LOG_WARN("failed to eval arg expr", K(ret)); + } else { + expr->locate_expr_datum(eval_ctx_) = *datum; + expr->set_evaluated_projected(eval_ctx_); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.value_exprs_.count(); ++i) { + ObExpr *expr = MY_SPEC.value_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + if (OB_FAIL(arg_expr->eval_batch(eval_ctx_, *child_brs_->skip_, child_brs_->size_))) { + LOG_WARN("failed to eval batch for arg expr", K(ret)); + } else { + ObDatum *datums = expr->locate_batch_datums(eval_ctx_); + ObDatum *arg_datums = arg_expr->locate_batch_datums(eval_ctx_); + MEMCPY(datums, arg_datums, brs_.size_ * sizeof(ObDatum)); + expr->set_evaluated_projected(eval_ctx_); + } + } + if (OB_SUCC(ret)) { + cur_part_idx_++; + } + return ret; +} + +int ObUnpivotV2Op::batch_copy_data() +{ + int ret = OB_SUCCESS; + int64_t pos = 0; + brs_.set_all_rows_active(true); + for (int64_t i = 0; OB_SUCC(ret) && i < brs_.size_; ++i) { + if (child_brs_->skip_->at(i + offset_)) { + brs_.set_skip(i); + brs_.set_all_rows_active(false); + } else { + brs_.reset_skip(i); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.origin_exprs_.count(); ++ i) { + ObExpr *expr = MY_SPEC.origin_exprs_.at(i); + ObDatum *buffer_datums = buffer_ + pos; + if (expr->is_batch_result()) { + ObDatum *datums = expr->locate_batch_datums(eval_ctx_); + MEMCPY(datums, buffer_datums + offset_, brs_.size_ * sizeof(ObDatum)); + pos += child_brs_->size_; + } else { + // expr that is not batch result do not need modify datum; + // do nothing + } + expr->set_evaluated_projected(eval_ctx_); + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.label_exprs_.count(); ++ i) { + ObExpr *expr = MY_SPEC.label_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + ObDatum *datum = NULL; + if (OB_FAIL(arg_expr->eval(eval_ctx_, datum))) { + LOG_WARN("failed to eval arg expr", K(ret)); + } else { + expr->locate_expr_datum(eval_ctx_) = *datum; + expr->set_evaluated_projected(eval_ctx_); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.value_exprs_.count(); ++ i) { + ObExpr *expr = MY_SPEC.value_exprs_.at(i); + ObExpr *arg_expr = expr->args_[cur_part_idx_]; + if (OB_FAIL(arg_expr->eval_batch(eval_ctx_, *child_brs_->skip_, child_brs_->size_))) { + LOG_WARN("failed to eval batch for arg expr", K(ret)); + } else { + ObDatum *datums = expr->locate_batch_datums(eval_ctx_); + ObDatum *arg_datums = arg_expr->locate_batch_datums(eval_ctx_); + MEMCPY(datums, (arg_datums + offset_), brs_.size_ * sizeof(ObDatum)); + expr->set_evaluated_projected(eval_ctx_); + } + } + if (OB_SUCC(ret)) { + offset_ += brs_.size_; + if (offset_ == child_brs_->size_) { + offset_ = 0; + cur_part_idx_++; + } + } + return ret; +} + +int ObUnpivotV2Op::get_result_buffer() +{ + int ret = OB_SUCCESS; + if (!using_buffer_) { + int64_t pos = 0; + using_buffer_ = true; + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.origin_exprs_.count(); ++i) { + ObExpr *origin_expr = MY_SPEC.origin_exprs_.at(i); + ObDatum *datums = origin_expr->locate_batch_datums(eval_ctx_); + if (OB_FAIL(origin_expr->eval_batch(eval_ctx_, *child_brs_->skip_, child_brs_->size_))) { + LOG_WARN("failed to eval batch", K(ret)); + } else if (origin_expr->is_batch_result()) { + MEMCPY(buffer_ + pos, datums, child_brs_->size_ * sizeof(ObDatum)); + pos += child_brs_->size_; + } else { + // expr that is not batch result do not need buffer; + // do nothing + } + } + } + return ret; +} + +int ObUnpivotV2Op::restore_batch_if_need() +{ + int ret = OB_SUCCESS; + if (using_buffer_) { + int64_t pos = 0; + for (int64_t i = 0; OB_SUCC(ret) && i < MY_SPEC.origin_exprs_.count(); ++i) { + ObExpr *origin_expr = MY_SPEC.origin_exprs_.at(i); + ObDatum *datums = origin_expr->locate_batch_datums(eval_ctx_); + if (OB_FAIL(origin_expr->eval_batch(eval_ctx_, *child_brs_->skip_, child_brs_->size_))) { + LOG_WARN("failed to eval batch", K(ret)); + } else if (origin_expr->is_batch_result()) { + MEMCPY(datums, buffer_ + pos, child_brs_->size_ * sizeof(ObDatum)); + pos += child_brs_->size_; + } else { + // expr that is not batch result do not need buffer; + // do nothing + } + } + using_buffer_ = false; + } + return ret; +} + +void ObUnpivotV2Op::destroy() +{ + ObOperator::destroy(); +} + +void ObUnpivotV2Op::reset() +{ + cur_part_idx_ = -1; + offset_ = 0; + child_brs_ = NULL; + using_buffer_ = false; +} + } // end namespace sql } // end namespace oceanbase diff --git a/src/sql/engine/subquery/ob_unpivot_op.h b/src/sql/engine/subquery/ob_unpivot_op.h index 76b9b591dc..53f1b1929a 100644 --- a/src/sql/engine/subquery/ob_unpivot_op.h +++ b/src/sql/engine/subquery/ob_unpivot_op.h @@ -14,12 +14,47 @@ #define OCEANBASE_SRC_SQL_ENGINE_SUBQUERY_OB_UNPIVOT_OP_H_ #include "sql/engine/ob_operator.h" -#include "sql/resolver/dml/ob_dml_stmt.h" namespace oceanbase { namespace sql { + +class ObVectorsResultHolder; + +struct ObUnpivotInfo +{ +public: + OB_UNIS_VERSION(1); +public: + ObUnpivotInfo() + : is_include_null_(false), + old_column_count_(0), + for_column_count_(0), + unpivot_column_count_(0) + {} + ObUnpivotInfo(const bool is_include_null, const int64_t old_column_count, + const int64_t for_column_count, const int64_t unpivot_column_count) + : is_include_null_(is_include_null), old_column_count_(old_column_count), + for_column_count_(for_column_count), unpivot_column_count_(unpivot_column_count) + {} + + void reset() { new (this) ObUnpivotInfo(); } + OB_INLINE bool has_unpivot() const + { return old_column_count_>= 0 && unpivot_column_count_ > 0 && for_column_count_ > 0; }; + OB_INLINE int64_t get_new_column_count() const + { return unpivot_column_count_ + for_column_count_; } + OB_INLINE int64_t get_output_column_count() const + { return old_column_count_ + get_new_column_count(); } + TO_STRING_KV(K_(is_include_null), K_(old_column_count), K_(unpivot_column_count), + K_(for_column_count)); + + bool is_include_null_; + int64_t old_column_count_; + int64_t for_column_count_; + int64_t unpivot_column_count_; +}; + class ObUnpivotSpec : public ObOpSpec { OB_UNIS_VERSION(1); @@ -54,6 +89,61 @@ private: DISALLOW_COPY_AND_ASSIGN(ObUnpivotOp); }; +class ObUnpivotV2Spec : public ObOpSpec +{ + OB_UNIS_VERSION(1); +public: + ObUnpivotV2Spec(common::ObIAllocator &alloc, const ObPhyOperatorType type); + + INHERIT_TO_STRING_KV("op_spec", ObOpSpec, K_(origin_exprs), K_(label_exprs), + K_(value_exprs), K_(is_include_null)); + + ExprFixedArray origin_exprs_; + ExprFixedArray label_exprs_; + ExprFixedArray value_exprs_; + bool is_include_null_; +private: + DISALLOW_COPY_AND_ASSIGN(ObUnpivotV2Spec); +}; + +class ObUnpivotV2Op : public ObOperator +{ +public: + ObUnpivotV2Op(ObExecContext &exec_ctx, const ObOpSpec &spec, ObOpInput *input); + virtual int inner_open() override; + virtual int inner_close() override; + virtual int inner_rescan() override; + virtual int inner_get_next_batch(const int64_t max_row_cnt) override; + virtual int inner_get_next_row() override + { + return OB_NOT_IMPLEMENT; + } + virtual void destroy() override; + +private: + void reset(); + int next_batch(const int64_t max_row_cnt); + int next_vector(const int64_t max_row_cnt); + int project_vector(); + int project_vector_with_offset(); + int batch_project_data(); + int batch_copy_data(); + int get_result_buffer(); + int restore_batch_if_need(); + int get_row_in_batch(int64_t rid); + int get_child_batch_if_need(int64_t batch_size); + int64_t cur_part_idx_; + int64_t offset_; + const ObBatchRows *child_brs_; + union + { + ObDatum *buffer_; + ObVectorsResultHolder *vec_holder_; + }; + bool using_buffer_; + DISALLOW_COPY_AND_ASSIGN(ObUnpivotV2Op); +}; + } // namespace sql } // namespace oceanbase diff --git a/src/sql/optimizer/ob_log_group_by.cpp b/src/sql/optimizer/ob_log_group_by.cpp index 6406fe3492..4892fe8651 100644 --- a/src/sql/optimizer/ob_log_group_by.cpp +++ b/src/sql/optimizer/ob_log_group_by.cpp @@ -79,7 +79,8 @@ int ObLogGroupBy::get_explain_name_internal(char *buf, } if (OB_SUCC(ret) && from_pivot_) { - ret = BUF_PRINTF(" PIVOT"); + // Don't mark this for now, and add it after specific optimization is done. + // ret = BUF_PRINTF(" PIVOT"); } if (OB_FAIL(ret)) { diff --git a/src/sql/optimizer/ob_log_join.cpp b/src/sql/optimizer/ob_log_join.cpp index 1932bff5a0..6c316eeb5d 100644 --- a/src/sql/optimizer/ob_log_join.cpp +++ b/src/sql/optimizer/ob_log_join.cpp @@ -704,8 +704,8 @@ const ObLogicalOperator *ObLogJoin::find_child_join(const ObLogicalOperator *op) bool ObLogJoin::is_scan_operator(log_op_def::ObLogOpType type) { return LOG_TABLE_SCAN == type || LOG_SUBPLAN_SCAN == type || - LOG_FUNCTION_TABLE == type || LOG_UNPIVOT == type || - LOG_TEMP_TABLE_ACCESS == type || LOG_JSON_TABLE == type || LOG_VALUES_TABLE_ACCESS == type; + LOG_FUNCTION_TABLE == type || LOG_TEMP_TABLE_ACCESS == type || + LOG_JSON_TABLE == type || LOG_VALUES_TABLE_ACCESS == type; } int ObLogJoin::append_used_join_hint(ObIArray &used_hints) diff --git a/src/sql/optimizer/ob_log_plan.cpp b/src/sql/optimizer/ob_log_plan.cpp index fe91a6dd02..c5d5fe8ad8 100644 --- a/src/sql/optimizer/ob_log_plan.cpp +++ b/src/sql/optimizer/ob_log_plan.cpp @@ -11504,7 +11504,6 @@ int ObLogPlan::adjust_final_plan_info(ObLogicalOperator *&op) op->set_child(i, child); if (op->get_type() == log_op_def::LOG_SET || op->get_type() == log_op_def::LOG_SUBPLAN_SCAN || - op->get_type() == log_op_def::LOG_UNPIVOT || (op->get_type() == log_op_def::LOG_SUBPLAN_FILTER && i > 0)) { child->mark_is_plan_root(); child->get_plan()->set_plan_root(child); diff --git a/src/sql/optimizer/ob_log_subplan_scan.cpp b/src/sql/optimizer/ob_log_subplan_scan.cpp index 093abfb1ce..63f273fbac 100644 --- a/src/sql/optimizer/ob_log_subplan_scan.cpp +++ b/src/sql/optimizer/ob_log_subplan_scan.cpp @@ -31,7 +31,6 @@ int ObLogSubPlanScan::generate_access_exprs() LOG_WARN("get unexpected null", K(col_item), K(ret)); } else if (col_item->table_id_ == subquery_id_ && col_item->expr_->is_explicited_reference() && - !col_item->expr_->is_unpivot_mocked_column() && OB_FAIL(access_exprs_.push_back(col_item->expr_))) { LOG_WARN("failed to push back expr", K(ret)); } else { /*do nothing*/ } diff --git a/src/sql/optimizer/ob_log_unpivot.cpp b/src/sql/optimizer/ob_log_unpivot.cpp index 79c33a3612..6315f6db83 100644 --- a/src/sql/optimizer/ob_log_unpivot.cpp +++ b/src/sql/optimizer/ob_log_unpivot.cpp @@ -19,9 +19,9 @@ using namespace oceanbase::common; int ObLogUnpivot::get_op_exprs(ObIArray &all_exprs) { int ret = OB_SUCCESS; - if (OB_FAIL(generate_access_exprs())) { - LOG_WARN("failed to generate access exprs", K(ret)); - } else if (OB_FAIL(append(all_exprs, access_exprs_))) { + if (OB_FAIL(append(all_exprs, origin_exprs_)) + || OB_FAIL(append(all_exprs, label_exprs_)) + || OB_FAIL(append(all_exprs, value_exprs_))) { LOG_WARN("failed to append exprs", K(ret)); } else if (OB_FAIL(ObLogicalOperator::get_op_exprs(all_exprs))) { LOG_WARN("failed to get op exprs", K(ret)); @@ -29,90 +29,11 @@ int ObLogUnpivot::get_op_exprs(ObIArray &all_exprs) return ret; } -int ObLogUnpivot::generate_access_exprs() +int ObLogUnpivot::is_my_fixed_expr(const ObRawExpr *expr, bool &is_fixed) { - int ret = OB_SUCCESS; - const ObDMLStmt *stmt = NULL; - ObSEArray column_exprs; - if (OB_ISNULL(get_plan()) || OB_ISNULL(stmt = get_plan()->get_stmt())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(get_plan()), K(stmt), K(ret)); - } else if (OB_FAIL(stmt->get_column_exprs(get_subquery_id(), column_exprs))) { - LOG_WARN("failed to get column exprs", K(ret)); - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < column_exprs.count(); i++) { - ObRawExpr *expr = NULL; - if (OB_ISNULL(expr = column_exprs.at(i))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("ColumnItem has a NULL expr", K(expr), K(ret)); - } else if (expr->is_explicited_reference() && - OB_FAIL(access_exprs_.push_back(expr))) { - LOG_WARN("failed to push back exprs", K(ret)); - } else if (OB_FAIL(add_var_to_array_no_dup(access_exprs_, static_cast(expr)))){ - LOG_PRINT_EXPR(WARN, "failed to add expr to access", expr, K(ret)); - } else { /*do nothing*/ } - } - } - return ret; -} - -bool ObLogUnpivot::is_in_old_columns(const ObSelectStmt &select_stmt, - const ObUnpivotInfo &unpivot_info, - ObRawExpr *expr) -{ - int ret = OB_SUCCESS; - bool is_in = false; - if (0 == unpivot_info.old_column_count_) { - //do nothing - } else { - for (int64_t j = 0; OB_SUCC(ret) && j < unpivot_info_.old_column_count_; ++j) { - if (expr == select_stmt.get_select_item(j).expr_) { - is_in = true; - break; - } - } - } - return is_in; -} - -int ObLogUnpivot::allocate_expr_post(ObAllocExprContext &ctx) -{ - int ret = OB_SUCCESS; - for (int64_t i = 0; OB_SUCC(ret) && i < access_exprs_.count(); ++i) { - if (OB_ISNULL(access_exprs_.at(i)) || OB_UNLIKELY(!access_exprs_.at(i)->is_column_ref_expr())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected error", K(ret)); - } else { - ObColumnRefRawExpr *expr = static_cast(access_exprs_.at(i)); - LOG_PRINT_EXPR(DEBUG, "succ to add expr to access", expr, "producer", id_); - if (OB_FAIL(mark_expr_produced(expr, branch_id_, id_, ctx))) { - LOG_PRINT_EXPR(WARN, "failed to mark expr as produced", expr, "producer", id_); - } else { - LOG_PRINT_EXPR(DEBUG, "succ to produce expr", expr, "producer", id_, K(expr)); - if (!is_plan_root()) { - if (!expr->is_unpivot_mocked_column()) { - if (OB_FAIL(add_var_to_array_no_dup(output_exprs_, - static_cast(expr)))) { - LOG_PRINT_EXPR(WARN, "failed to add expr to output_exprs_", expr, K(ret)); - } else { - LOG_PRINT_EXPR(DEBUG, "succ to add expr to output_exprs_", expr, K(ret)); - } - } else { - LOG_PRINT_EXPR(DEBUG, "expr in unpivot no need output", expr, K(ret)); - } - } else { - LOG_PRINT_EXPR(DEBUG, "succ to add expr to output_exprs_", expr, K(ret)); - } - } - } - } - - if(OB_SUCC(ret)) { - if (OB_FAIL(ObLogicalOperator::allocate_expr_post(ctx))) { - LOG_WARN("failed to allocate expr post", K(ret)); - } else { /*do nothing*/ } - } - return ret; + is_fixed = ObOptimizerUtil::find_item(label_exprs_, expr) || + ObOptimizerUtil::find_item(value_exprs_, expr); + return OB_SUCCESS; } int ObLogUnpivot::get_plan_item_info(PlanText &plan_text, @@ -123,108 +44,44 @@ int ObLogUnpivot::get_plan_item_info(PlanText &plan_text, LOG_WARN("failed to get plan item info", K(ret)); } else { BEGIN_BUF_PRINT; - if (OB_FAIL(BUF_PRINTF("unpivot(%s,%ld,%ld,%ld), ", - unpivot_info_.is_include_null_ ? "include" : "exclude", - unpivot_info_.old_column_count_, - unpivot_info_.for_column_count_, - unpivot_info_.unpivot_column_count_))) { - LOG_WARN("BUF_PRINTF fails", K(ret)); - } else if (OB_FAIL(BUF_PRINTF("\n "))) { + if (OB_FAIL(BUF_PRINTF("unpivot(%s)", + is_include_null_ ? "include null" : "exclude null"))) { LOG_WARN("BUF_PRINTF fails", K(ret)); } else { /* Do nothing */ } END_BUF_PRINT(plan_item.special_predicates_, plan_item.special_predicates_len_); } - if (OB_SUCC(ret)) { - BEGIN_BUF_PRINT; - const ObIArray &access = get_access_exprs(); - EXPLAIN_PRINT_EXPRS(access, type); - END_BUF_PRINT(plan_item.access_predicates_, - plan_item.access_predicates_len_); - } - if (OB_SUCC(ret)) { - ObString &name = get_subquery_name(); - BUF_PRINT_OB_STR(name.ptr(), - name.length(), - plan_item.object_alias_, - plan_item.object_alias_len_); - } return ret; } -int ObLogUnpivot::compute_sharding_info() +int ObLogUnpivot::do_re_est_cost(EstimateCostInfo ¶m, double &card, double &op_cost, double &cost) { int ret = OB_SUCCESS; ObLogicalOperator *child = NULL; - const ObSelectStmt *child_stmt = NULL; - if (OB_ISNULL(child = get_child(first_child)) - || OB_ISNULL(child->get_stmt()) || OB_ISNULL(get_plan())) { + const int64_t parallel = param.need_parallel_; + int part_count = label_exprs_.at(0)->get_param_count(); + if (OB_ISNULL(child = get_child(ObLogicalOperator::first_child)) || OB_ISNULL(get_plan())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(child), K(get_plan())); - } else if (OB_UNLIKELY(!child->get_stmt()->is_select_stmt())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected stmt type", K(child->get_stmt()->get_stmt_type()), K(ret)); - } else if (FALSE_IT(child_stmt = static_cast(child->get_stmt()))) { - /*do nothing*/ - } else if (!child->is_distributed()) { - ret = ObLogicalOperator::compute_sharding_info(); } else { - for (int64_t i = -1; OB_SUCC(ret) && i < child->get_weak_sharding().count(); ++i) { - bool exist_in_unpivot = false; - bool is_inherited_sharding = false; - ObShardingInfo *sharding = - (i == -1) ? child->get_strong_sharding() : child->get_weak_sharding().at(i); - if (NULL != sharding) { - for (int64_t j = unpivot_info_.old_column_count_; - !exist_in_unpivot && j < child_stmt->get_select_items().count(); ++j) { - const ObRawExpr *expr = child_stmt->get_select_item(j).expr_; - exist_in_unpivot = ObOptimizerUtil::find_item(sharding->get_partition_keys(), expr) - || ObOptimizerUtil::find_item(sharding->get_sub_partition_keys(), expr); - } - // Only inherit the sharding when partition keys do not exist in the unpivot - // "for" clause, because those columns will be output by unpivot op directly. - if (-1 == i) { - // strong sharding - if (exist_in_unpivot) { - // strong sharding, can not inherit - strong_sharding_ = get_plan()->get_optimizer_context().get_distributed_sharding(); - inherit_sharding_index_ = -1; - } else { - // strong sharding, can inherit - if (OB_FAIL(ObJoinOrder::convert_subplan_scan_sharding_info(*get_plan(), - *child, - subquery_id_, - true, // is_strong - sharding, - strong_sharding_, - is_inherited_sharding))) { - LOG_WARN("failed to convert sharding info", K(ret)); - } else { - inherit_sharding_index_ = is_inherited_sharding ? 0 : -1; - } - } - } else if (!exist_in_unpivot) { - // weak sharding, can inherit - ObShardingInfo *temp_sharding = NULL; - if (OB_FAIL(ObJoinOrder::convert_subplan_scan_sharding_info(*get_plan(), - *child, - subquery_id_, - false, // is_strong - sharding, - temp_sharding, - is_inherited_sharding))) { - LOG_WARN("failed to convert sharding info", K(ret)); - } else if (OB_NOT_NULL(temp_sharding)) { - inherit_sharding_index_ = 0; - if (OB_FAIL(weak_sharding_.push_back(temp_sharding))) { - LOG_WARN("failed to push back weak sharding", K(ret)); - } - } - } else { /* weak sharding, can not inherit, do nothing */ } + double child_card = child->get_card(); + double child_cost = child->get_cost(); + if (param.need_row_count_ >= 0) { + if (param.need_row_count_ < get_card()) { + param.need_row_count_ /= part_count; + } else { + param.need_row_count_ = -1; } } - if (OB_SUCC(ret)) { - LOG_TRACE("succeed to convert unpovit scan sharding info", KPC(strong_sharding_), K(weak_sharding_), K(inherit_sharding_index_)); + if (OB_FAIL(SMART_CALL(child->re_est_cost(param, child_card, child_cost)))) { + LOG_WARN("failed to re est exchange cost", K(ret)); + } else { + ObOptimizerContext &opt_ctx = get_plan()->get_optimizer_context(); + op_cost = ObOptEstCost::cost_filter_rows(child_card / parallel, + get_filter_exprs(), + opt_ctx); + cost = child_cost + op_cost; + card = child_card * part_count; } } return ret; @@ -266,7 +123,7 @@ int ObLogUnpivot::est_cost() ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected parallel degree", K(parallel), K(ret)); } else { - card_ = child->get_card(); + card_ = child->get_card() * (label_exprs_.at(0)->get_param_count()); ObOptimizerContext &opt_ctx = get_plan()->get_optimizer_context(); op_cost_ = ObOptEstCost::cost_filter_rows(card_ /parallel, get_filter_exprs(), @@ -276,41 +133,23 @@ int ObLogUnpivot::est_cost() return ret; } +int ObLogUnpivot::inner_replace_op_exprs(ObRawExprReplacer &replacer) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(replace_exprs_action(replacer, origin_exprs_))) { + LOG_WARN("failed to replace key exprs", K(ret)); + } else if (OB_FAIL(replace_exprs_action(replacer, label_exprs_))) { + LOG_WARN("failed to replace for exprs", K(ret)); + } else if (OB_FAIL(replace_exprs_action(replacer, value_exprs_))) { + LOG_WARN("failed to replace val exprs", K(ret)); + } + return ret; +} + int ObLogUnpivot::compute_op_ordering() { int ret = OB_SUCCESS; - ObSEArray ordering_exprs; - if (OB_ISNULL(get_stmt()) - || OB_UNLIKELY(!get_stmt()->is_select_stmt()) - || OB_UNLIKELY(!get_stmt()->is_unpivot_select())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("stmt is invalid", K(ret)); - } else { - ObLogicalOperator *child = NULL; - if (OB_ISNULL(child= get_child(ObLogicalOperator::first_child))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("operator does not have child", K(ret)); - } - bool found = true; - const ObSelectStmt &select_stmt = *static_cast(get_stmt()); - const ObUnpivotInfo &unpivot_info = select_stmt.get_unpivot_info(); - for (int64_t j = 0; OB_SUCC(ret) && found && j < child->get_op_ordering().count(); ++j) { - if (is_in_old_columns(select_stmt, unpivot_info, child->get_op_ordering().at(j).expr_)) { - if (OB_FAIL(ordering_exprs.push_back(child->get_op_ordering().at(j).expr_))) { - LOG_WARN("failed to push back", K(ret)); - } - } else { - found = false; - } - } - - if (OB_SUCC(ret)) { - if (OB_FAIL(ObOptimizerUtil::make_sort_keys(ordering_exprs, get_op_ordering()))) { - LOG_WARN("failed to copy sort keys", K(ret)); - } - } - LOG_DEBUG("finish compute_op_ordering", K(unpivot_info), K(get_op_ordering())); - } + reset_op_ordering(); return ret; } @@ -322,110 +161,6 @@ int ObLogUnpivot::compute_fd_item_set() return ret; } -int ObLogUnpivot::compute_const_exprs() -{ - // output_const_exprs should be the intersection of 'const_expr of child' and 'old_columns' - int ret = OB_SUCCESS; - ObLogicalOperator *child = NULL; - if (OB_ISNULL(my_plan_) || OB_UNLIKELY(get_num_of_child() < 0) || - OB_ISNULL(get_stmt()) || OB_UNLIKELY(!get_stmt()->is_select_stmt()) || - OB_UNLIKELY(!get_stmt()->is_unpivot_select())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("operator is invalid", K(ret), K(get_num_of_child()), K(my_plan_)); - } else if (OB_UNLIKELY(get_num_of_child() == 0)) { - /*do nothing*/ - } else if (OB_ISNULL(child = get_child(0))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("child is null", K(ret), K(child)); - } else { - const ObSelectStmt &select_stmt = static_cast(*get_stmt()); - const ObUnpivotInfo &unpivot_info = select_stmt.get_unpivot_info(); - const ObIArray &child_output_const_exprs= child->get_output_const_exprs(); - if (0 == unpivot_info.old_column_count_ || child_output_const_exprs.empty()) { - //do nothing - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < child_output_const_exprs.count(); ++i) { - if (is_in_old_columns(select_stmt, unpivot_info, child_output_const_exprs.at(i))) { - if (OB_FAIL(output_const_exprs_.push_back(child_output_const_exprs.at(i)))) { - LOG_WARN("failed to push back", K(ret)); - } - } - } - } - if (OB_FAIL(ret) || filter_exprs_.empty()) { - /*do nothing*/ - } else if (OB_FAIL(ObOptimizerUtil::compute_const_exprs(filter_exprs_, output_const_exprs_))) { - LOG_WARN("failed to compute const conditionexprs", K(ret)); - } else {/*do nothing*/} - } - return ret; -} - -int ObLogUnpivot::compute_equal_set() -{ - int ret = OB_SUCCESS; - ObLogicalOperator *child = NULL; - EqualSets *ordering_esets = NULL; - EqualSets *old_col_esets = NULL; - if (OB_ISNULL(my_plan_) || OB_UNLIKELY(get_num_of_child() < 0) || - OB_ISNULL(get_stmt()) || OB_UNLIKELY(!get_stmt()->is_select_stmt()) || - OB_UNLIKELY(!get_stmt()->is_unpivot_select())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("operator is invalid", K(ret), K(get_num_of_child()), K(my_plan_)); - } else if (OB_UNLIKELY(get_num_of_child() == 0)) { - // do nothing - } else if (OB_ISNULL(child = get_child(0))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("child is null", K(ret), K(child)); - } else if (OB_ISNULL(old_col_esets = get_plan()->create_equal_sets())) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("failed to create equal sets", K(ret)); - } else { - // get old_col_esets (equal set of old columns) - const EqualSets &child_esets = child->get_output_equal_sets(); - const ObSelectStmt &select_stmt = static_cast(*get_stmt()); - const ObUnpivotInfo &unpivot_info = select_stmt.get_unpivot_info(); - for (int64_t i = 0; OB_SUCC(ret) && i < child_esets.count(); ++i) { - ObSEArray eset_builder; - EqualSet *child_eset = child_esets.at(i); - if (OB_ISNULL(child_eset)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected null", K(ret), K(child_eset)); - } - for (int64_t j = 0; OB_SUCC(ret) && j < child_eset->count(); ++j) { - if (is_in_old_columns(select_stmt, unpivot_info, child_eset->at(j))) { - if (OB_FAIL(eset_builder.push_back(child_eset->at(j)))) { - LOG_WARN("failed to push back", K(ret)); - } - } - } - if (OB_SUCC(ret) && OB_FAIL(ObRawExprSetUtils::add_expr_set( - &get_plan()->get_allocator(), eset_builder, *old_col_esets))) { - LOG_WARN("failed to add expr set", K(ret)); - } - } - - // compute equal set of unpivot log plan - if (OB_FAIL(ret)) { - } else if (filter_exprs_.empty()) { - // inherit equal sets from old_col_esets - set_output_equal_sets(old_col_esets); - } else if (OB_ISNULL(ordering_esets = get_plan()->create_equal_sets())) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("failed to create equal sets", K(ret)); - } else if (OB_FAIL(ObEqualAnalysis::compute_equal_set( - &my_plan_->get_allocator(), - filter_exprs_, - *old_col_esets, - *ordering_esets))) { - LOG_WARN("failed to compute ordering output equal set", K(ret)); - } else { - set_output_equal_sets(ordering_esets); - } - } - return ret; -} - int ObLogUnpivot::compute_one_row_info() { int ret = OB_SUCCESS; @@ -433,8 +168,60 @@ int ObLogUnpivot::compute_one_row_info() return ret; } -int ObLogUnpivot::is_my_fixed_expr(const ObRawExpr *expr, bool &is_fixed) +uint64_t ObLogUnpivot::hash(uint64_t seed) const { - is_fixed = ObOptimizerUtil::find_item(access_exprs_, expr); - return OB_SUCCESS; + uint64_t hash_value = seed; + hash_value = do_hash(is_include_null_, hash_value); + hash_value = ObLogicalOperator::hash(hash_value); + return hash_value; +} + +int ObLogUnpivot::compute_sharding_info() +{ + int ret = OB_SUCCESS; + ObLogicalOperator *child = NULL; + if (OB_ISNULL(child = get_child(first_child)) || OB_ISNULL(get_plan())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(child), K(get_plan())); + } else if (!child->is_distributed()) { + ret = ObLogicalOperator::compute_sharding_info(); + } else { + for (int64_t i = -1; OB_SUCC(ret) && i < child->get_weak_sharding().count(); ++i) { + bool is_inherited_sharding = false; + ObShardingInfo *sharding = (i == -1) ? child->get_strong_sharding() : child->get_weak_sharding().at(i); + bool keep_origin = OB_ISNULL(sharding) ? false : + (ObOptimizerUtil::subset_exprs(sharding->get_partition_keys(), origin_exprs_) && + ObOptimizerUtil::subset_exprs(sharding->get_sub_partition_keys(), origin_exprs_)); + // Only inherit the sharding when partition keys do not exist in the unpivot + // "for" clause, because those columns will be output by unpivot op directly. + if (-1 == i) { + // strong sharding + if (keep_origin) { + // can inherit + strong_sharding_ = sharding; + inherit_sharding_index_ = ObLogicalOperator::first_child; + } else { + // can not inherit + strong_sharding_ = get_plan()->get_optimizer_context().get_distributed_sharding(); + inherit_sharding_index_ = -1; + } + } else { + // weak sharding + if (keep_origin) { + // can inherit + if (OB_FAIL(weak_sharding_.push_back(sharding))) { + LOG_WARN("failed to push back weak sharding", K(ret)); + } else { + inherit_sharding_index_ = ObLogicalOperator::first_child; + } + } else { + // weak sharding, can not inherit, do nothing + } + } + } + if (OB_SUCC(ret)) { + LOG_TRACE("succeed to convert unpovit sharding info", KPC(strong_sharding_), K(weak_sharding_), K(inherit_sharding_index_)); + } + } + return ret; } diff --git a/src/sql/optimizer/ob_log_unpivot.h b/src/sql/optimizer/ob_log_unpivot.h index 808112d294..7fd8ec0053 100644 --- a/src/sql/optimizer/ob_log_unpivot.h +++ b/src/sql/optimizer/ob_log_unpivot.h @@ -13,7 +13,6 @@ #ifndef _OB_LOG_UNPIVOT_H_ #define _OB_LOG_UNPIVOT_H_ #include "sql/optimizer/ob_logical_operator.h" -#include "sql/resolver/dml/ob_dml_stmt.h" namespace oceanbase @@ -25,41 +24,46 @@ class ObLogUnpivot : public ObLogicalOperator public: ObLogUnpivot(ObLogPlan &plan) : ObLogicalOperator(plan), - subquery_id_(common::OB_INVALID_ID), - subquery_name_(), - access_exprs_() + origin_exprs_(), + label_exprs_(), + value_exprs_(), + is_include_null_(false) {} ~ObLogUnpivot() {} + + inline common::ObIArray &get_origin_exprs() { return origin_exprs_; } + inline common::ObIArray &get_label_exprs() { return label_exprs_; } + inline common::ObIArray &get_value_exprs() { return value_exprs_; } + int set_origin_exprs(const common::ObIArray &origin_exprs) { return origin_exprs_.assign(origin_exprs); } + int set_label_exprs(const common::ObIArray &label_exprs) { return label_exprs_.assign(label_exprs); } + int set_value_exprs(const common::ObIArray &value_exprs) { return value_exprs_.assign(value_exprs); } + + inline bool is_include_null() { return is_include_null_; } + inline bool is_exclude_null() { return !is_include_null_; } + inline void set_include_null(bool is_include_null) { is_include_null_ = is_include_null; } + virtual int inner_replace_op_exprs(ObRawExprReplacer &replacer) override; virtual int get_op_exprs(ObIArray &all_exprs) override; virtual int is_my_fixed_expr(const ObRawExpr *expr, bool &is_fixed) override; - virtual int allocate_expr_post(ObAllocExprContext &ctx); - virtual int compute_sharding_info() override; - virtual int est_cost() override; - virtual int est_width() override; - void set_subquery_id(uint64_t subquery_id) { subquery_id_ = subquery_id; } - inline const uint64_t &get_subquery_id() const { return subquery_id_; } - inline common::ObString &get_subquery_name() { return subquery_name_; } - inline const common::ObIArray &get_access_exprs() const { return access_exprs_; } - inline common::ObIArray &get_access_exprs() { return access_exprs_; } - virtual int compute_op_ordering() override; - virtual int compute_fd_item_set() override; - virtual int compute_const_exprs() override; - virtual int compute_equal_set() override; - virtual int compute_one_row_info() override; virtual int get_plan_item_info(PlanText &plan_text, ObSqlPlanItem &plan_item) override; + virtual int do_re_est_cost(EstimateCostInfo ¶m, double &card, double &op_cost, double &cost) override; + + virtual int est_cost() override; + virtual int est_width() override; + virtual int compute_op_ordering() override; + virtual int compute_fd_item_set() override; + virtual int compute_one_row_info() override; + virtual uint64_t hash(uint64_t seed) const override; + virtual int compute_sharding_info() override; + + VIRTUAL_TO_STRING_KV(K_(origin_exprs), K_(label_exprs), K_(value_exprs), K_(is_include_null)); + private: - int generate_access_exprs(); - bool is_in_old_columns(const ObSelectStmt &select_stmt, - const ObUnpivotInfo &unpivot_info, - ObRawExpr *expr); -public: - uint64_t subquery_id_; - common::ObString subquery_name_; - common::ObArray access_exprs_; - ObUnpivotInfo unpivot_info_; -private: + common::ObSEArray origin_exprs_; + common::ObSEArray label_exprs_; + common::ObSEArray value_exprs_; + bool is_include_null_; DISALLOW_COPY_AND_ASSIGN(ObLogUnpivot); }; diff --git a/src/sql/optimizer/ob_logical_operator.cpp b/src/sql/optimizer/ob_logical_operator.cpp index 554b84702b..93db6d268e 100644 --- a/src/sql/optimizer/ob_logical_operator.cpp +++ b/src/sql/optimizer/ob_logical_operator.cpp @@ -1407,7 +1407,7 @@ int ObLogicalOperator::get_plan_item_info(PlanText &plan_text, plan_item.projection_len_); } // print filter - if (OB_SUCC(ret) && !filter_exprs_.empty() && LOG_UNPIVOT != get_type()) { + if (OB_SUCC(ret) && !filter_exprs_.empty()) { const ObIArray &filter = filter_exprs_; BEGIN_BUF_PRINT; EXPLAIN_PRINT_EXPRS(filter, type); @@ -3772,7 +3772,7 @@ int ObLogicalOperator::set_plan_root_output_exprs() const ObSelectStmt *sel_stmt = static_cast(get_stmt()); bool is_unpivot = (LOG_UNPIVOT == type_ && sel_stmt->is_unpivot_select()); uint64_t min_cluster_version = GET_MIN_CLUSTER_VERSION(); - if (!sel_stmt->has_select_into() && OB_FAIL(sel_stmt->get_select_exprs(output_exprs_, is_unpivot))) { + if (!sel_stmt->has_select_into() && OB_FAIL(sel_stmt->get_select_exprs(output_exprs_))) { LOG_WARN("failed to get select exprs", K(ret)); } else { /*do nothing*/ } } else if (stmt->is_returning()) { diff --git a/src/sql/optimizer/ob_optimizer_util.cpp b/src/sql/optimizer/ob_optimizer_util.cpp index 76c6e5da1a..50a0a7f48e 100644 --- a/src/sql/optimizer/ob_optimizer_util.cpp +++ b/src/sql/optimizer/ob_optimizer_util.cpp @@ -6807,7 +6807,6 @@ int ObOptimizerUtil::gen_set_target_list(ObIAllocator *allocator, new_select_item.params_idx_ = select_item.params_idx_; new_select_item.neg_param_idx_ = select_item.neg_param_idx_; new_select_item.esc_str_flag_ = select_item.esc_str_flag_; - new_select_item.is_unpivot_mocked_column_ = select_item.is_unpivot_mocked_column_; new_select_item.paramed_alias_name_ = select_item.paramed_alias_name_; new_select_item.need_check_dup_name_ = select_item.need_check_dup_name_; if (OB_FAIL(ObRawExprUtils::make_set_op_expr(*expr_factory, i, set_op_type, @@ -6917,6 +6916,69 @@ int ObOptimizerUtil::get_set_res_types(ObIAllocator *allocator, return ret; } +int ObOptimizerUtil::check_oracle_mode_set_type_validity(bool is_ps_prepare_stage, + const ObExprResType &left_type, + const ObExprResType &right_type, + bool is_distinct /* = false */, + bool *skip_add_cast /* = NULL */) { + int ret = OB_SUCCESS; + /* + * Oracle has more strict constraints for data types used in set operator + * https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries004.htm + */ + // need to refine this when more data type are added in oracle mode + if (!((left_type.is_null() && !right_type.is_lob() && !right_type.is_lob_locator()) + || (left_type.is_null() && (right_type.is_lob() || right_type.is_lob_locator()) && !is_distinct) + || (right_type.is_null() && !left_type.is_lob() && !left_type.is_lob_locator()) + || (right_type.is_null() && (left_type.is_lob() || left_type.is_lob_locator()) && !is_distinct) + || (left_type.is_raw() && right_type.is_raw()) + || (left_type.is_character_type() && right_type.is_character_type()) + || (ob_is_oracle_numeric_type(left_type.get_type()) && ob_is_oracle_numeric_type(right_type.get_type())) + || (ob_is_oracle_temporal_type(left_type.get_type()) && (ob_is_oracle_temporal_type(right_type.get_type()))) + || (left_type.is_urowid() && right_type.is_urowid()) + || (left_type.is_lob() && right_type.is_lob() && left_type.get_collation_type() == right_type.get_collation_type()) + || (left_type.is_geometry() && right_type.is_geometry()) + || (left_type.is_lob_locator() && right_type.is_lob_locator() && left_type.get_collation_type() == right_type.get_collation_type()) + || ((ob_is_user_defined_sql_type(left_type.get_type()) || ob_is_user_defined_pl_type(left_type.get_type())) + && (ob_is_user_defined_sql_type(right_type.get_type()) || ob_is_user_defined_pl_type(right_type.get_type()))))) { + // || (left_type.is_lob() && right_type.is_lob() && !is_distinct))) { + // Originally, cases like "select clob from t union all select blob from t" return errorif (is_ps_prepare_stage) { + if (is_ps_prepare_stage) { + if (skip_add_cast != NULL) { + *skip_add_cast = true; + } + LOG_WARN("ps prepare stage expression has different datatype", K(left_type), K(right_type)); + } else { + ret = OB_ERR_EXP_NEED_SAME_DATATYPE; + LOG_WARN("expression must have same datatype as corresponding expression", K(ret), + K(right_type.is_varchar_or_char()), K(left_type), K(right_type)); + } + } else if (left_type.is_character_type() && + right_type.is_character_type() && + (left_type.is_varchar_or_char() != right_type.is_varchar_or_char())) { + ret = OB_ERR_CHARACTER_SET_MISMATCH; + LOG_WARN("character set mismatch", K(ret), K(left_type), K(right_type)); + } else if (left_type.is_string_or_lob_locator_type() && + right_type.is_string_or_lob_locator_type()) { + ObCharsetType left_cs = left_type.get_charset_type(); + ObCharsetType right_cs = right_type.get_charset_type(); + if (left_cs != right_cs) { + if (CHARSET_UTF8MB4 == left_cs || CHARSET_UTF8MB4 == right_cs) { + //sys table column exist utf8 varchar types, let it go + } else { + ret = OB_ERR_COLLATION_MISMATCH; //ORA-12704 + LOG_WARN("character set mismatch", K(ret), K(left_cs), K(right_cs)); + } + } + } else if (is_distinct && (right_type.is_geometry() || left_type.is_geometry())) { + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + LOG_WARN("column type incompatible", K(ret), K(left_type), K(right_type)); + } + return ret; +} + + + /* * Oracle has more strict constraints for data types used in set operator * https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries004.htm @@ -6933,50 +6995,9 @@ int ObOptimizerUtil::check_set_child_res_types(const ObExprResType &left_type, const bool is_oracle_mode = lib::is_oracle_mode(); if (left_type != right_type || ob_is_enumset_tc(right_type.get_type()) || is_mysql_recursive_union) { if (is_oracle_mode) { - if (!((left_type.is_null() && !right_type.is_lob() && !right_type.is_lob_locator()) - || (left_type.is_null() && (right_type.is_lob() || right_type.is_lob_locator()) && !is_distinct) - || (right_type.is_null() && !left_type.is_lob() && !left_type.is_lob_locator()) - || (right_type.is_null() && (left_type.is_lob() || left_type.is_lob_locator()) && !is_distinct) - || (left_type.is_raw() && right_type.is_raw()) - || (left_type.is_character_type() && right_type.is_character_type()) - || (ob_is_oracle_numeric_type(left_type.get_type()) && ob_is_oracle_numeric_type(right_type.get_type())) - || (ob_is_oracle_temporal_type(left_type.get_type()) && (ob_is_oracle_temporal_type(right_type.get_type()))) - || (left_type.is_urowid() && right_type.is_urowid()) - || (left_type.is_lob() && right_type.is_lob() && left_type.get_collation_type() == right_type.get_collation_type()) - || (left_type.is_geometry() && right_type.is_geometry()) - || (left_type.is_lob_locator() && right_type.is_lob_locator() && left_type.get_collation_type() == right_type.get_collation_type()) - || ((ob_is_user_defined_sql_type(left_type.get_type()) || ob_is_user_defined_pl_type(left_type.get_type())) - && (ob_is_user_defined_sql_type(right_type.get_type()) || ob_is_user_defined_pl_type(right_type.get_type()))))) { - // || (left_type.is_lob() && right_type.is_lob() && !is_distinct))) { - // Originally, cases like "select clob from t union all select blob from t" return errorif (is_ps_prepare_stage) { - if (is_ps_prepare_stage) { - skip_add_cast = true; - LOG_WARN("ps prepare stage expression has different datatype", K(left_type), K(right_type)); - } else { - ret = OB_ERR_EXP_NEED_SAME_DATATYPE; - LOG_WARN("expression must have same datatype as corresponding expression", K(ret), - K(right_type.is_varchar_or_char()), K(left_type), K(right_type)); - } - } else if (left_type.is_character_type() && - right_type.is_character_type() && - (left_type.is_varchar_or_char() != right_type.is_varchar_or_char())) { - ret = OB_ERR_CHARACTER_SET_MISMATCH; - LOG_WARN("character set mismatch", K(ret), K(left_type), K(right_type)); - } else if (left_type.is_string_or_lob_locator_type() && - right_type.is_string_or_lob_locator_type()) { - ObCharsetType left_cs = left_type.get_charset_type(); - ObCharsetType right_cs = right_type.get_charset_type(); - if (left_cs != right_cs) { - if (CHARSET_UTF8MB4 == left_cs || CHARSET_UTF8MB4 == right_cs) { - //sys table column exist utf8 varchar types, let it go - } else { - ret = OB_ERR_COLLATION_MISMATCH; //ORA-12704 - LOG_WARN("character set mismatch", K(ret), K(left_cs), K(right_cs)); - } - } - } else if (is_distinct && (right_type.is_geometry() || left_type.is_geometry())) { - ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; - LOG_WARN("column type incompatible", K(ret), K(left_type), K(right_type)); + if (OB_FAIL(check_oracle_mode_set_type_validity( + is_ps_prepare_stage, left_type, right_type, is_distinct, &skip_add_cast))) { + LOG_WARN("left and right type of set operator not valid in oracle mode", K(ret)); } } if (OB_SUCC(ret) && is_mysql_recursive_union && left_type.is_null()) { diff --git a/src/sql/optimizer/ob_optimizer_util.h b/src/sql/optimizer/ob_optimizer_util.h index 179d4bb01f..627ed1614a 100644 --- a/src/sql/optimizer/ob_optimizer_util.h +++ b/src/sql/optimizer/ob_optimizer_util.h @@ -1184,6 +1184,13 @@ public: ObIArray *res_types, const bool is_mysql_recursive_union = false, ObIArray *rcte_col_name = NULL); + + static int check_oracle_mode_set_type_validity(bool is_ps_prepare_stage, + const ObExprResType &left_type, + const ObExprResType &right_type, + bool is_distinct = false, + bool *skip_add_cast = NULL); + static int add_cast_to_set_list(ObSQLSessionInfo *session_info, ObRawExprFactory *expr_factory, ObIArray &stmts, diff --git a/src/sql/optimizer/ob_raw_expr_add_to_context.cpp b/src/sql/optimizer/ob_raw_expr_add_to_context.cpp index c6836e01ef..50f0c1f538 100644 --- a/src/sql/optimizer/ob_raw_expr_add_to_context.cpp +++ b/src/sql/optimizer/ob_raw_expr_add_to_context.cpp @@ -121,6 +121,11 @@ int ObRawExprAddToContext::visit(ObMatchFunRawExpr &expr) return add_expr(expr); } +int ObRawExprAddToContext::visit(ObUnpivotRawExpr &expr) +{ + return add_expr(expr); +} + /** * TODO(jiuman): the complexity of the algorithm used in add_expr is quite high. * We may need to revisit it later if it turns out to be an optimization we have * to do. diff --git a/src/sql/optimizer/ob_raw_expr_add_to_context.h b/src/sql/optimizer/ob_raw_expr_add_to_context.h index 6c7b0bf6e4..ec286e1d8a 100644 --- a/src/sql/optimizer/ob_raw_expr_add_to_context.h +++ b/src/sql/optimizer/ob_raw_expr_add_to_context.h @@ -50,6 +50,7 @@ namespace sql { virtual int visit(ObPseudoColumnRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); private: int add_expr(ObRawExpr &expr); // types and constants diff --git a/src/sql/optimizer/ob_raw_expr_check_dep.cpp b/src/sql/optimizer/ob_raw_expr_check_dep.cpp index a9a36a6bfe..62d579dafe 100644 --- a/src/sql/optimizer/ob_raw_expr_check_dep.cpp +++ b/src/sql/optimizer/ob_raw_expr_check_dep.cpp @@ -84,7 +84,8 @@ int ObRawExprCheckDep::check(const ObRawExpr &expr) case ObRawExpr::EXPR_OPERATOR: case ObRawExpr::EXPR_SET_OP: case ObRawExpr::EXPR_CASE_OPERATOR: - case ObRawExpr::EXPR_WINDOW: { + case ObRawExpr::EXPR_WINDOW: + case ObRawExpr::EXPR_UNPIVOT: { if (OB_FAIL(check_expr(expr, found))) { LOG_WARN("failed to check expr", K(expr), K(ret)); } else if (!found) { diff --git a/src/sql/optimizer/ob_raw_expr_get_hash_value.cpp b/src/sql/optimizer/ob_raw_expr_get_hash_value.cpp index 2eb638ecbe..dbe211959c 100644 --- a/src/sql/optimizer/ob_raw_expr_get_hash_value.cpp +++ b/src/sql/optimizer/ob_raw_expr_get_hash_value.cpp @@ -89,3 +89,9 @@ int ObRawExprGetHashValue::visit(ObMatchFunRawExpr &expr) seed_ = expr.hash(seed_); return OB_SUCCESS; } + +int ObRawExprGetHashValue::visit(ObUnpivotRawExpr &expr) +{ + seed_ = expr.hash(seed_); + return OB_SUCCESS; +} diff --git a/src/sql/optimizer/ob_raw_expr_get_hash_value.h b/src/sql/optimizer/ob_raw_expr_get_hash_value.h index ab92bb2075..270967f36b 100644 --- a/src/sql/optimizer/ob_raw_expr_get_hash_value.h +++ b/src/sql/optimizer/ob_raw_expr_get_hash_value.h @@ -46,6 +46,7 @@ namespace sql { virtual int visit(ObSetOpRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); private: int add_expr(ObRawExpr &expr); diff --git a/src/sql/optimizer/ob_select_log_plan.cpp b/src/sql/optimizer/ob_select_log_plan.cpp index 857d665943..77e1f5f0f2 100644 --- a/src/sql/optimizer/ob_select_log_plan.cpp +++ b/src/sql/optimizer/ob_select_log_plan.cpp @@ -5562,9 +5562,9 @@ int ObSelectLogPlan::allocate_plan_top() if (OB_SUCC(ret) && select_stmt->is_unpivot_select()) { // group-by or rollup both allocate group by logical operator. if (OB_FAIL(candi_allocate_unpivot())) { - LOG_WARN("failed to allocate unpovit operator", K(ret)); + LOG_WARN("failed to allocate unpivot operator", K(ret)); } else { - LOG_TRACE("succeed to allocate unpovit operator", + LOG_TRACE("succeed to allocate unpivot operator", K(candidates_.candidate_plans_.count())); } } @@ -9074,12 +9074,14 @@ int ObSelectLogPlan::allocate_unpivot_as_top(ObLogicalOperator *&old_top) { int ret = OB_SUCCESS; const ObDMLStmt *stmt = static_cast(get_stmt()); + const ObUnpivotItem *unpivot_item = NULL; ObLogUnpivot *unpivot = NULL; if (OB_ISNULL(old_top) || OB_ISNULL(stmt) || OB_UNLIKELY(!stmt->is_unpivot_select()) || OB_UNLIKELY(stmt->get_table_items().empty()) - || OB_ISNULL(stmt->get_table_item(0))) { + || OB_ISNULL(stmt->get_table_item(0)) + || OB_ISNULL(unpivot_item = stmt->get_unpivot_item())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Get unexpected null", K(ret), K(old_top), KPC(stmt)); } else if (OB_ISNULL(unpivot = static_cast @@ -9088,12 +9090,19 @@ int ObSelectLogPlan::allocate_unpivot_as_top(ObLogicalOperator *&old_top) LOG_ERROR("failed to allocate subquery operator", K(ret)); } else { const TableItem *table_item = stmt->get_table_item(0); - unpivot->unpivot_info_ = stmt->get_unpivot_info(); - unpivot->set_subquery_id(table_item->table_id_); - unpivot->get_subquery_name().assign_ptr(table_item->table_name_.ptr(), - table_item->table_name_.length()); unpivot->set_child(ObLogicalOperator::first_child, old_top); - if (OB_FAIL(unpivot->compute_property())) { + unpivot->set_include_null(unpivot_item->is_include_null_); + if (OB_UNLIKELY(unpivot_item->label_exprs_.count() <= 0) || + OB_ISNULL(unpivot_item->label_exprs_.at(0))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid unpivot info", K(ret)); + } else if (OB_FAIL(unpivot->set_origin_exprs(unpivot_item->origin_exprs_))) { + LOG_WARN("failed to set key exprs", K(ret)); + } else if (OB_FAIL(unpivot->set_label_exprs(unpivot_item->label_exprs_))) { + LOG_WARN("failed to set for exprs", K(ret)); + } else if (OB_FAIL(unpivot->set_value_exprs(unpivot_item->value_exprs_))) { + LOG_WARN("failed to set val exprs", K(ret)); + } else if (OB_FAIL(unpivot->compute_property())) { LOG_WARN("failed to compute property", K(ret)); } else { old_top = unpivot; diff --git a/src/sql/printer/ob_dml_stmt_printer.cpp b/src/sql/printer/ob_dml_stmt_printer.cpp index 3e54b4dfa4..6fad59bae4 100644 --- a/src/sql/printer/ob_dml_stmt_printer.cpp +++ b/src/sql/printer/ob_dml_stmt_printer.cpp @@ -13,6 +13,13 @@ #define USING_LOG_PREFIX SQL #include "ob_dml_stmt_printer.h" #include "sql/printer/ob_select_stmt_printer.h" +#include "sql/ob_sql_context.h" +#include "sql/resolver/dml/ob_del_upd_stmt.h" +#include "common/ob_smart_call.h" +#include "lib/charset/ob_charset.h" +#include "sql/optimizer/ob_log_plan.h" +#include "sql/monitor/ob_sql_plan.h" +#include "sql/resolver/dml/ob_transpose_resolver.h" namespace oceanbase { using namespace common; @@ -271,6 +278,205 @@ int ObDMLStmtPrinter::print_table_with_subquery(const TableItem *table_item) return ret; } +int ObDMLStmtPrinter::print_table_with_transpose(const TableItem *table_item) +{ + int ret = OB_SUCCESS; + TransposeDef *trans_def = NULL; + if (OB_ISNULL(table_item) || + OB_ISNULL(trans_def = table_item->transpose_table_def_) || + OB_ISNULL(trans_def->orig_table_item_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(print_table(trans_def->orig_table_item_))) { + LOG_WARN("failed to print origin table", K(ret)); + } else if (trans_def->is_pivot()) { + PivotDef *pivot_def = static_cast (trans_def); + DATA_PRINTF(" PIVOT ("); + for (int64_t i = 0; OB_SUCC(ret) && i < pivot_def->aggr_pairs_.count(); ++i) { + const PivotDef::AggrPair &aggr_pair = pivot_def->aggr_pairs_.at(i); + HEAP_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf) { + MEMSET(expr_str_buf, 0 , sizeof(expr_str_buf)); + int64_t pos = 0; + ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, + schema_guard_, stmt_->get_query_ctx()->get_timezone_info()); + if (OB_FAIL(expr_printer.do_print(aggr_pair.expr_, T_NONE_SCOPE, true))) { + LOG_WARN("print expr definition failed", KPC(aggr_pair.expr_), K(ret)); + } else { + DATA_PRINTF("%.*s", static_cast(pos), expr_str_buf); + } + } + if (OB_SUCC(ret) && !aggr_pair.alias_name_.empty()) { + DATA_PRINTF(" AS "); + PRINT_IDENT_WITH_QUOT(aggr_pair.alias_name_); + } + if (i != pivot_def->aggr_pairs_.count() - 1) { + DATA_PRINTF(","); + } + } + + DATA_PRINTF(" FOR "); + if (OB_SUCC(ret)) { + if (pivot_def->for_columns_.count() == 1) { + PRINT_IDENT_WITH_QUOT(pivot_def->for_column_names_[0]); + } else { + DATA_PRINTF("("); + for (int64_t i = 0; i < pivot_def->for_columns_.count() && OB_SUCC(ret); ++i) { + PRINT_IDENT_WITH_QUOT(pivot_def->for_column_names_[i]); + DATA_PRINTF(","); + } + if (OB_SUCC(ret)) { + --(*pos_); + DATA_PRINTF(")"); + } + } + } + + DATA_PRINTF(" IN ("); + for (int64_t i = 0; OB_SUCC(ret) && i < pivot_def->in_pairs_.count(); ++i) { + const PivotDef::InPair &in_pair = pivot_def->in_pairs_.at(i); + if (OB_SUCC(ret) && !in_pair.const_exprs_.empty()) { + if (OB_SUCC(ret)) { + HEAP_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf) { + MEMSET(expr_str_buf, 0 , sizeof(expr_str_buf)); + if (in_pair.const_exprs_.count() == 1) { + ObRawExpr *expr = in_pair.const_exprs_.at(0); + int64_t pos = 0; + ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, + schema_guard_, stmt_->get_query_ctx()->get_timezone_info()); + if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { + LOG_WARN("print expr definition failed", KPC(expr), K(ret)); + } else { + DATA_PRINTF("%.*s", static_cast(pos), expr_str_buf); + } + } else { + DATA_PRINTF("("); + for (int64_t j = 0; j < in_pair.const_exprs_.count() && OB_SUCC(ret); ++j) { + ObRawExpr *expr = in_pair.const_exprs_.at(j); + int64_t pos = 0; + ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, + schema_guard_, stmt_->get_query_ctx()->get_timezone_info()); + if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { + LOG_WARN("print expr definition failed", KPC(expr), K(ret)); + } else { + DATA_PRINTF("%.*s,", static_cast(pos), expr_str_buf); + } + } + if (OB_SUCC(ret)) { + --(*pos_); + DATA_PRINTF(")"); + } + } + } + } + } + DATA_PRINTF(" AS "); + PRINT_IDENT_WITH_QUOT(in_pair.name_); + if (i != pivot_def->in_pairs_.count() - 1) { + DATA_PRINTF(","); + } + } + DATA_PRINTF(")"); // in ( + DATA_PRINTF(")"); // pivot ( + + } else if (trans_def->is_unpivot()) { + UnpivotDef *unpivot_def = static_cast (trans_def); + DATA_PRINTF(" UNPIVOT %s (", (unpivot_def->is_include_null() ? "INCLUDE NULLS" : "EXCLUDE NULLS")); + if (OB_SUCC(ret)) { + if (unpivot_def->value_columns_.count() == 1) { + PRINT_IDENT_WITH_QUOT(unpivot_def->value_columns_[0]); + } else { + DATA_PRINTF("("); + for (int64_t i = 0; i < unpivot_def->value_columns_.count() && OB_SUCC(ret); ++i) { + PRINT_IDENT_WITH_QUOT(unpivot_def->value_columns_[i]); + DATA_PRINTF(","); + } + if (OB_SUCC(ret)) { + --(*pos_); + DATA_PRINTF(")"); + } + } + } + + DATA_PRINTF(" FOR "); + if (OB_SUCC(ret)) { + if (unpivot_def->label_columns_.count() == 1) { + PRINT_IDENT_WITH_QUOT(unpivot_def->label_columns_[0]); + } else { + DATA_PRINTF("("); + for (int64_t i = 0; i < unpivot_def->label_columns_.count() && OB_SUCC(ret); ++i) { + PRINT_IDENT_WITH_QUOT(unpivot_def->label_columns_[i]); + DATA_PRINTF(","); + } + if (OB_SUCC(ret)) { + --(*pos_); + DATA_PRINTF(")"); + } + } + } + + DATA_PRINTF(" IN ("); + for (int64_t i = 0; i < unpivot_def->in_pairs_.count() && OB_SUCC(ret); ++i) { + const UnpivotDef::InPair &in_pair = unpivot_def->in_pairs_[i]; + if (in_pair.column_names_.count() == 1) { + PRINT_IDENT_WITH_QUOT(in_pair.column_names_[0]); + } else { + DATA_PRINTF("("); + for (int64_t j = 0; j < in_pair.column_names_.count() && OB_SUCC(ret); ++j) { + PRINT_IDENT_WITH_QUOT(in_pair.column_names_[j]); + DATA_PRINTF(","); + } + if (OB_SUCC(ret)) { + --(*pos_); + DATA_PRINTF(")"); + } + } + + if (OB_SUCC(ret) && !in_pair.const_exprs_.empty()) { + DATA_PRINTF(" AS "); + if (OB_SUCC(ret)) { + HEAP_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf) { + MEMSET(expr_str_buf, 0 , sizeof(expr_str_buf)); + if (in_pair.const_exprs_.count() == 1) { + ObRawExpr *expr = in_pair.const_exprs_.at(0); + int64_t pos = 0; + ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, + schema_guard_, stmt_->get_query_ctx()->get_timezone_info()); + if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { + LOG_WARN("print expr definition failed", KPC(expr), K(ret)); + } else { + DATA_PRINTF("%.*s", static_cast(pos), expr_str_buf); + } + } else { + DATA_PRINTF("("); + for (int64_t j = 0; j < in_pair.const_exprs_.count() && OB_SUCC(ret); ++j) { + ObRawExpr *expr = in_pair.const_exprs_.at(j); + int64_t pos = 0; + ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, + schema_guard_, stmt_->get_query_ctx()->get_timezone_info()); + if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { + LOG_WARN("print expr definition failed", KPC(expr), K(ret)); + } else { + DATA_PRINTF("%.*s,", static_cast(pos), expr_str_buf); + } + } + if (OB_SUCC(ret)) { + --(*pos_); + DATA_PRINTF(")"); + } + } + } + } + } + if (i != unpivot_def->in_pairs_.count() - 1) { + DATA_PRINTF(","); + } + } + DATA_PRINTF(")"); + DATA_PRINTF(")"); + } + return ret; +} + int ObDMLStmtPrinter::print_table(const TableItem *table_item, bool no_print_alias/*default false*/) { @@ -423,6 +629,13 @@ int ObDMLStmtPrinter::print_table(const TableItem *table_item, if (table_item->alias_name_.length() > 0) { DATA_PRINTF(" %.*s", LEN_AND_PTR(table_item->alias_name_)); } + } else if (NULL != table_item->transpose_table_def_) { + if (OB_FAIL(print_table_with_transpose(table_item))) { + LOG_WARN("failed to print table with transpose", K(ret)); + } else if (!no_print_alias) { + DATA_PRINTF(" "); + PRINT_IDENT_WITH_QUOT(table_item->alias_name_); + } } else if (OB_FAIL(print_table_with_subquery(table_item))) { LOG_WARN("failed to print table with subquery", K(ret)); } diff --git a/src/sql/printer/ob_dml_stmt_printer.h b/src/sql/printer/ob_dml_stmt_printer.h index bffa34545f..4bd806f100 100644 --- a/src/sql/printer/ob_dml_stmt_printer.h +++ b/src/sql/printer/ob_dml_stmt_printer.h @@ -115,6 +115,7 @@ public: int print_values_table_to_union_all(const TableItem &table_item, bool no_print_alias); int print_table(const TableItem *table_item, bool no_print_alias = false); + int print_table_with_transpose(const TableItem *table_item); int print_table_with_subquery(const TableItem *table_item); int print_base_table(const TableItem *table_item); int prepare_dblink_hint(ObQueryHint &query_hint_dblink); diff --git a/src/sql/printer/ob_raw_expr_printer.cpp b/src/sql/printer/ob_raw_expr_printer.cpp index f6aed7e610..33fbf8398f 100644 --- a/src/sql/printer/ob_raw_expr_printer.cpp +++ b/src/sql/printer/ob_raw_expr_printer.cpp @@ -271,6 +271,11 @@ int ObRawExprPrinter::print(ObRawExpr *expr) } break; } + case ObRawExpr::EXPR_UNPIVOT: { + ObUnpivotRawExpr *unpivot_expr = static_cast(expr); + PRINT_EXPR(unpivot_expr); + break; + } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unknown expr class", K(ret), K(expr->get_expr_class())); diff --git a/src/sql/printer/ob_select_stmt_printer.cpp b/src/sql/printer/ob_select_stmt_printer.cpp index d2401ca821..292c94ad93 100644 --- a/src/sql/printer/ob_select_stmt_printer.cpp +++ b/src/sql/printer/ob_select_stmt_printer.cpp @@ -50,12 +50,7 @@ int ObSelectStmtPrinter::do_print() schema_guard_, print_params_, param_store_); - if (stmt_->is_unpivot_select()) { - if (OB_FAIL(print_unpivot())) { - LOG_WARN("fail to print_unpivot", - KPC(stmt_->get_transpose_item()), K(ret)); - } - } else if (OB_FAIL(SMART_CALL(print()))) { + if (OB_FAIL(SMART_CALL(print()))) { LOG_WARN("fail to print stmt", KPC(stmt_), K(ret)); } } @@ -97,150 +92,6 @@ int ObSelectStmtPrinter::print() return ret; } -int ObSelectStmtPrinter::print_unpivot() -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(stmt_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("stmt_ should not be NULL", K(ret)); - } else if (OB_UNLIKELY(!stmt_->is_select_stmt()) - || OB_UNLIKELY(!stmt_->is_unpivot_select()) - || OB_UNLIKELY(stmt_->get_table_items().count() != 1) - || OB_ISNULL(stmt_->get_table_item(0)->ref_query_) - || OB_UNLIKELY(stmt_->get_table_item(0)->ref_query_->get_table_items().count() != 1) - ) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Not a valid select stmt", K(stmt_->get_stmt_type()), - K(stmt_->get_table_items().count()), K(ret)); - } else { - const ObSelectStmt *select_stmt = static_cast(stmt_); - - if (OB_FAIL(print_temp_table_as_cte())) { - LOG_WARN("failed to print cte", K(ret)); - } - - if (OB_SUCC(ret)) { - if (OB_FAIL(print_select())) { - LOG_WARN("fail to print select", K(ret), K(*stmt_)); - } - } - - DATA_PRINTF(" FROM "); - - if (OB_SUCC(ret)) { - if (OB_FAIL(print_table(stmt_->get_table_item(0)->ref_query_->get_table_item(0)))) { - LOG_WARN("fail to print table", K(ret)); - } - } - - const TransposeItem &transpose_item = *select_stmt->get_transpose_item(); - - if (OB_SUCC(ret)) { - DATA_PRINTF(" UNPIVOT %s (", - (transpose_item.is_include_null() ? "INCLUDE NULLS" : "EXCLUDE NULLS")); - } - - if (OB_SUCC(ret)) { - if (transpose_item.unpivot_columns_.count() == 1) { - PRINT_IDENT_WITH_QUOT(transpose_item.unpivot_columns_[0]); - } else { - DATA_PRINTF("("); - for (int64_t i = 0; i < transpose_item.unpivot_columns_.count() && OB_SUCC(ret); ++i) { - PRINT_IDENT_WITH_QUOT(transpose_item.unpivot_columns_[i]); - DATA_PRINTF(","); - } - if (OB_SUCC(ret)) { - --(*pos_); - DATA_PRINTF(")"); - } - } - } - - DATA_PRINTF(" FOR "); - - if (OB_SUCC(ret)) { - if (transpose_item.for_columns_.count() == 1) { - PRINT_IDENT_WITH_QUOT(transpose_item.for_columns_[0]); - } else { - DATA_PRINTF("("); - for (int64_t i = 0; i < transpose_item.for_columns_.count() && OB_SUCC(ret); ++i) { - PRINT_IDENT_WITH_QUOT(transpose_item.for_columns_[i]); - DATA_PRINTF(","); - } - if (OB_SUCC(ret)) { - --(*pos_); - DATA_PRINTF(")"); - } - } - } - - DATA_PRINTF(" IN ("); - - if (OB_SUCC(ret)) { - for (int64_t i = 0; i < transpose_item.in_pairs_.count() && OB_SUCC(ret); ++i) { - const TransposeItem::InPair &in_pair = transpose_item.in_pairs_[i]; - if (in_pair.column_names_.count() == 1) { - PRINT_IDENT_WITH_QUOT(in_pair.column_names_[0]); - } else { - DATA_PRINTF("("); - for (int64_t j = 0; j < in_pair.column_names_.count() && OB_SUCC(ret); ++j) { - PRINT_IDENT_WITH_QUOT(in_pair.column_names_[j]); - DATA_PRINTF(","); - } - if (OB_SUCC(ret)) { - --(*pos_); - DATA_PRINTF(")"); - } - } - - if (OB_SUCC(ret) && !in_pair.exprs_.empty()) { - DATA_PRINTF(" AS "); - if (OB_SUCC(ret)) { - HEAP_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf) { - MEMSET(expr_str_buf, 0 , sizeof(expr_str_buf)); - if (in_pair.exprs_.count() == 1) { - ObRawExpr *expr = in_pair.exprs_.at(0); - int64_t pos = 0; - ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, - schema_guard_, stmt_->get_query_ctx()->get_timezone_info()); - if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { - LOG_WARN("print expr definition failed", KPC(expr), K(ret)); - } else { - DATA_PRINTF("%.*s", static_cast(pos), expr_str_buf); - } - } else { - DATA_PRINTF("("); - for (int64_t j = 0; j < in_pair.exprs_.count() && OB_SUCC(ret); ++j) { - ObRawExpr *expr = in_pair.exprs_.at(j); - int64_t pos = 0; - ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, - schema_guard_, stmt_->get_query_ctx()->get_timezone_info()); - if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { - LOG_WARN("print expr definition failed", KPC(expr), K(ret)); - } else { - DATA_PRINTF("%.*s,", static_cast(pos), expr_str_buf); - } - } - if (OB_SUCC(ret)) { - --(*pos_); - DATA_PRINTF(")"); - } - } - } - } - } - if (i != transpose_item.in_pairs_.count() - 1) { - DATA_PRINTF(","); - } - } - DATA_PRINTF(")"); - } - - DATA_PRINTF(")"); - } - - return ret; -} int ObSelectStmtPrinter::print_set_op_stmt() { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/dml/ob_column_namespace_checker.cpp b/src/sql/resolver/dml/ob_column_namespace_checker.cpp index 8c0d88faf5..d8aa84a40f 100644 --- a/src/sql/resolver/dml/ob_column_namespace_checker.cpp +++ b/src/sql/resolver/dml/ob_column_namespace_checker.cpp @@ -87,22 +87,34 @@ int ObColumnNamespaceChecker::check_table_column_namespace(const ObQualifiedName } else {/*do nothing*/} } else { ObTableItemIterator table_item_iter(*this); - while (OB_SUCC(ret) && (cur_table = table_item_iter.get_next_table_item()) != NULL) { + if (is_transpose_) { + // 解析 pivot 时需要仅从origin table中解析聚合函数,此时需要这样一个屏蔽其他table item的方式 + cur_table = origin_table_; if (OB_FAIL(find_column_in_table(*cur_table, q_name, table_item, need_check_unique))) { if (OB_ERR_BAD_FIELD_ERROR == ret) { ret = OB_SUCCESS; - //continue to search } else { LOG_WARN("find column in table failed", K(ret)); } - } else { - break; //found column in table + } + } else { + while (OB_SUCC(ret) && (cur_table = table_item_iter.get_next_table_item()) != NULL) { + if (OB_FAIL(find_column_in_table(*cur_table, q_name, table_item, need_check_unique))) { + if (OB_ERR_BAD_FIELD_ERROR == ret) { + ret = OB_SUCCESS; + //continue to search + } else { + LOG_WARN("find column in table failed", K(ret)); + } + } else { + break; //found column in table + } } } if (OB_SUCC(ret) && NULL == table_item) { ret = OB_ERR_BAD_FIELD_ERROR; } - if (OB_SUCC(ret) && need_check_unique) { + if (OB_SUCC(ret) && need_check_unique && !is_transpose_) { //check table column whether unique in all tables const TableItem *tmp_table = NULL; bool tmp_check = false; diff --git a/src/sql/resolver/dml/ob_column_namespace_checker.h b/src/sql/resolver/dml/ob_column_namespace_checker.h index d8a4939679..af2cb88376 100644 --- a/src/sql/resolver/dml/ob_column_namespace_checker.h +++ b/src/sql/resolver/dml/ob_column_namespace_checker.h @@ -47,6 +47,8 @@ public: equal_columns_(), cur_joined_table_(NULL), check_unique_(true), + origin_table_(NULL), + is_transpose_(false), join_infos_(NULL), dml_stmt_(NULL) {} @@ -103,6 +105,17 @@ public: int set_equal_columns(const common::ObIArray &columns); void clear_equal_columns(); void set_dml_stmt(const ObDMLStmt *dml_stmt) { dml_stmt_ = dml_stmt; } + + void set_transpose_origin_table(const TableItem &table_item) + { + origin_table_ = &table_item; + is_transpose_ = true; + } + void clear_transpose() + { + origin_table_ = NULL; + is_transpose_ = false; + } private: int find_column_in_single_table(const TableItem &table_item, const ObQualifiedName &q_name, @@ -134,6 +147,8 @@ private: common::ObArray equal_columns_; // for merge stmt usage const TableItem *cur_joined_table_; bool check_unique_; + const TableItem *origin_table_; // for transpose table + bool is_transpose_; common::ObIArray *join_infos_; const ObDMLStmt *dml_stmt_; friend class ObTableItemIterator; diff --git a/src/sql/resolver/dml/ob_del_upd_resolver.cpp b/src/sql/resolver/dml/ob_del_upd_resolver.cpp index dcebede8f4..55991f5240 100644 --- a/src/sql/resolver/dml/ob_del_upd_resolver.cpp +++ b/src/sql/resolver/dml/ob_del_upd_resolver.cpp @@ -2463,7 +2463,7 @@ int ObDelUpdResolver::view_pullup_part_exprs() LOG_WARN("failed to add replace pair", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < sel_stmt->get_part_exprs().count(); ++i) { - ObDMLStmt::PartExprItem pei = sel_stmt->get_part_exprs().at(i); + PartExprItem pei = sel_stmt->get_part_exprs().at(i); if (pei.table_id_ != table->get_base_table_item().table_id_) { continue; } else if (OB_FAIL(copier.copy(pei.part_expr_, pei.part_expr_))) { @@ -2489,7 +2489,7 @@ int ObDelUpdResolver::view_pullup_part_exprs() } else if (OB_NOT_NULL(table_schema)) { const common::ObIArray &foreign_key_infos = table_schema->get_foreign_key_infos(); for (int64_t i = 0; OB_SUCC(ret) && i < sel_stmt->get_part_exprs().count(); ++i) { - ObDMLStmt::PartExprItem pei = sel_stmt->get_part_exprs().at(i); + PartExprItem pei = sel_stmt->get_part_exprs().at(i); if (!is_fk_parent_table(foreign_key_infos, pei.index_tid_)) { continue; } else if (OB_FAIL(copier.copy(pei.part_expr_, pei.part_expr_))) { diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index 62c0810a83..acfee44140 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -42,6 +42,7 @@ #include "share/external_table/ob_external_table_file_mgr.h" #include "sql/resolver/dcl/ob_dcl_resolver.h" #include "sql/resolver/ddl/ob_ddl_resolver.h" +#include "sql/resolver/dml/ob_transpose_resolver.h" namespace oceanbase { @@ -3538,9 +3539,6 @@ int ObDMLResolver::resolve_basic_table_without_cte(const ParseNode &parse_tree, if (parse_tree.num_child_ >= 6) { time_node = parse_tree.children_[5]; } - if (parse_tree.num_child_ >= 7) { - transpose_node = parse_tree.children_[6]; - } } } @@ -3587,8 +3585,6 @@ int ObDMLResolver::resolve_basic_table_without_cte(const ParseNode &parse_tree, table_item, is_reverse_link))) { LOG_WARN("resolve base or alias table item for dblink failed", K(ret)); - } else if (OB_FAIL(resolve_transpose_table(transpose_node, table_item))) { - LOG_WARN("resolve_transpose_table failed", K(ret)); } else if (NULL != time_node && OB_FAIL(resolve_flashback_query_node(time_node, table_item))) { LOG_WARN("failed to resolve flashback query node", K(ret)); } @@ -3718,12 +3714,6 @@ int ObDMLResolver::resolve_basic_table_without_cte(const ParseNode &parse_tree, if (OB_SUCCESS == ret && is_virtual_table(table_item->ref_id_)) { stmt->get_query_ctx()->is_contain_virtual_table_ = true; } - - if (OB_SUCCESS == ret) { - if (OB_FAIL(resolve_transpose_table(transpose_node, table_item))) { - LOG_WARN("resolve_transpose_table failed", K(ret)); - } - } } } LOG_DEBUG("finish resolve_basic_table", K(ret), KPC(table_item)); @@ -3776,7 +3766,7 @@ int ObDMLResolver::resolve_table_check_constraint_items(const TableItem *table_i } else if (OB_FAIL(generate_check_constraint_exprs(table_item, table_schema, stmt_constr_exprs, &check_flags))) { LOG_WARN("failed to add check constraint to stmt"); } else if (!stmt_constr_exprs.empty()) { - ObDMLStmt::CheckConstraintItem check_constraint_item; + CheckConstraintItem check_constraint_item; check_constraint_item.table_id_ = table_item->table_id_; check_constraint_item.ref_table_id_ = table_schema->get_table_id(); if (OB_FAIL(append(check_constraint_item.check_constraint_exprs_, stmt_constr_exprs))) { @@ -5372,9 +5362,6 @@ int ObDMLResolver::resolve_table(const ParseNode &parse_tree, if (parse_tree.num_child_ >= 6) { time_node = parse_tree.children_[5]; } - if (parse_tree.num_child_ >= 7) { - transpose_node = parse_tree.children_[6]; - } if (parse_tree.num_child_ >= 8 && OB_NOT_NULL(parse_tree.children_[7])) { ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("fetch clause can't occur in table attributes", K(ret)); @@ -5417,8 +5404,6 @@ int ObDMLResolver::resolve_table(const ParseNode &parse_tree, } else if (parse_tree.value_ != 1 && OB_FAIL(resolve_generate_table(*table_node, alias_node, table_item))) { LOG_WARN("resolve generate table failed", K(ret)); - } else if (OB_FAIL(resolve_transpose_table(transpose_node, table_item))) { - LOG_WARN("resolve_transpose_table failed", K(ret)); } else { params_.have_same_table_name_ = tmp_have_same_table; } @@ -5446,6 +5431,12 @@ int ObDMLResolver::resolve_table(const ParseNode &parse_tree, } else {/*do nothing*/} break; } + case T_TRANSPOSE_TABLE: { + if (OB_FAIL(resolve_transpose_table(*table_node, table_item))) { + LOG_WARN("failed to resolve transpose table", K(ret)); + } + break; + } case T_JOINED_TABLE: { JoinedTable *root = NULL; set_has_ansi_join(true); @@ -12713,7 +12704,6 @@ int ObDMLResolver::resolve_generated_table_column_item(const TableItem &table_it col_expr->set_result_type(select_expr->get_result_type()); col_expr->set_column_attr(table_item.get_table_name(), ref_select_item.alias_name_); col_expr->set_database_name(table_item.database_name_); - col_expr->set_unpivot_mocked_column(ref_select_item.is_unpivot_mocked_column_); if (table_item.alias_name_.empty()) { col_expr->set_synonym_db_name(table_item.synonym_db_name_); col_expr->set_synonym_name(table_item.synonym_name_); @@ -13014,986 +13004,17 @@ int ObDMLResolver::resolve_sample_clause(const ParseNode *sample_node, return ret; } -int ObDMLResolver::resolve_transpose_columns(const ParseNode &column_node, - ObIArray &columns) -{ - int ret = OB_SUCCESS; - if (column_node.type_ == T_COLUMN_LIST) { - if (OB_UNLIKELY(column_node.num_child_ <= 0) - || OB_ISNULL(column_node.children_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("column_node is unexpected", K(column_node.num_child_), - KP(column_node.children_), K(ret)); - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < column_node.num_child_; ++i) { - const ParseNode *tmp_node = column_node.children_[i]; - if (OB_ISNULL(tmp_node)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("column_node is unexpected", KP(tmp_node), K(ret)); - } else { - ObString column_name_(tmp_node->str_len_, tmp_node->str_value_); - if (OB_FAIL(columns.push_back(column_name_))) { - LOG_WARN("fail to push_back column_name_", K(column_name_), K(ret)); - } - } - } - } - } else { - ObString column_name(column_node.str_len_, column_node.str_value_); - if (OB_FAIL(columns.push_back(column_name))) { - LOG_WARN("fail to push_back column_name", K(column_name), K(ret)); - } - } - return ret; -} - -int ObDMLResolver::resolve_const_exprs(const ParseNode &expr_node, - ObIArray &const_exprs) -{ - int ret = OB_SUCCESS; - ObRawExpr *const_expr = NULL; - if (expr_node.type_ == T_EXPR_LIST) { - for (int64_t i = 0; OB_SUCC(ret) && i < expr_node.num_child_; ++i) { - const ParseNode *tmp_node = expr_node.children_[i]; - const_expr = NULL; - if (OB_ISNULL(tmp_node)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("tmp_node is unexpected", KP(tmp_node), K(ret)); - } else if (OB_FAIL(resolve_sql_expr(*tmp_node, const_expr))) { - LOG_WARN("fail to resolve_sql_expr", K(ret)); - } else if (OB_UNLIKELY(!const_expr->is_const_expr()) - || OB_UNLIKELY(const_expr->has_flag(ObExprInfoFlag::CNT_CUR_TIME))) { - ret = OB_ERR_NON_CONST_EXPR_IS_NOT_ALLOWED_FOR_PIVOT_UNPIVOT_VALUES; - LOG_WARN("non-constant expression is not allowed for pivot|unpivot values", - KPC(const_expr), K(ret)); - } else if (OB_FAIL(const_exprs.push_back(const_expr))) { - LOG_WARN("fail to push_back const_expr", KPC(const_expr), K(ret)); - } - } - } else { - if (OB_FAIL(resolve_sql_expr(expr_node, const_expr))) { - LOG_WARN("fail to resolve_sql_expr", K(ret)); - } else if (OB_UNLIKELY(!const_expr->is_const_expr()) - || OB_UNLIKELY(const_expr->has_flag(ObExprInfoFlag::CNT_CUR_TIME))) { - ret = OB_ERR_NON_CONST_EXPR_IS_NOT_ALLOWED_FOR_PIVOT_UNPIVOT_VALUES; - LOG_WARN("non-constant expression is not allowed for pivot|unpivot values", - KPC(const_expr), K(ret)); - } else if (OB_FAIL(const_exprs.push_back(const_expr))) { - LOG_WARN("fail to push_back const_expr", KPC(const_expr), K(ret)); - } - } - return ret; -} - -int ObDMLResolver::check_pivot_aggr_expr(ObRawExpr *expr) const -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(expr) || OB_UNLIKELY(!expr->has_flag(IS_AGG))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("aggr expr_ is unexpected", KPC(expr), K(ret)); - } else if (expr->get_expr_type() == T_FUN_GROUP_CONCAT) { - //succ - } else if (OB_UNLIKELY(static_cast(expr)->get_real_param_count() > 1)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("aggr expr_ has invalid argument", KPC(expr), K(ret)); - } else { - switch (expr->get_expr_type()) { - case T_FUN_MAX: - case T_FUN_MIN: - case T_FUN_SUM: - case T_FUN_COUNT: - case T_FUN_AVG: - case T_FUN_APPROX_COUNT_DISTINCT: - case T_FUN_STDDEV: - case T_FUN_VARIANCE: { - break; - } - default: { - ret = OB_ERR_EXPECT_AGGREGATE_FUNCTION_INSIDE_PIVOT_OPERATION; - LOG_WARN("expect aggregate function inside pivot operation", KPC(expr), K(ret)); - } - } - } - return ret; -} - -int ObDMLResolver::resolve_transpose_clause(const ParseNode &transpose_node, - TransposeItem &transpose_item, ObIArray &columns_in_aggrs) -{ - int ret = OB_SUCCESS; - if (OB_UNLIKELY(transpose_node.type_ != T_PIVOT && transpose_node.type_ != T_UNPIVOT) - || OB_UNLIKELY(transpose_node.num_child_ != 4) - || OB_ISNULL(transpose_node.children_) - || OB_ISNULL(transpose_node.children_[0]) - || OB_ISNULL(transpose_node.children_[1]) - || OB_ISNULL(transpose_node.children_[2]) - || OB_ISNULL(transpose_node.children_[3])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("transpose_node is unexpected", K(transpose_node.type_), K(transpose_node.num_child_), - KP(transpose_node.children_), K(ret)); - } else if (T_PIVOT == transpose_node.type_) { - transpose_item.set_pivot(); - - //pivot aggr - const ParseNode &aggr_node = *transpose_node.children_[0]; - if (OB_UNLIKELY(aggr_node.type_ != T_PIVOT_AGGR_LIST) - || OB_UNLIKELY(aggr_node.num_child_ <= 0) - || OB_ISNULL(aggr_node.children_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("aggr_node is unexpected", K(aggr_node.type_), K(aggr_node.num_child_), - KP(aggr_node.children_), K(ret)); - } else { - ObArray qualified_name_in_aggr; - for (int64_t i = 0; OB_SUCC(ret) && i < aggr_node.num_child_; ++i) { - const ParseNode *tmp_node = aggr_node.children_[i]; - const ParseNode *alias_node = NULL; - TransposeItem::AggrPair aggr_pair; - qualified_name_in_aggr.reuse(); - if (OB_ISNULL(tmp_node) - || OB_UNLIKELY(tmp_node->type_ != T_PIVOT_AGGR) - || OB_UNLIKELY(tmp_node->num_child_ != 2) - || OB_ISNULL(tmp_node->children_) - || OB_ISNULL(tmp_node->children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("tmp_node is unexpected", KP(tmp_node), K(ret)); - } else if (OB_FAIL(resolve_sql_expr(*tmp_node->children_[0], - aggr_pair.expr_, - &qualified_name_in_aggr))) { - LOG_WARN("fail to resolve_sql_expr", K(ret)); - } else if (OB_FAIL(check_pivot_aggr_expr(aggr_pair.expr_))) { - LOG_WARN("fail to check_aggr_expr", K(ret)); - } else if (NULL != (alias_node = tmp_node->children_[1]) - && FALSE_IT(aggr_pair.alias_name_.assign_ptr(alias_node->str_value_, - alias_node->str_len_))) { - } else if (OB_FAIL(transpose_item.aggr_pairs_.push_back(aggr_pair))) { - LOG_WARN("fail to push_back aggr_pair", K(aggr_pair), K(ret)); - } else { - for (int64_t j = 0; OB_SUCC(ret) && j < qualified_name_in_aggr.count(); ++j) { - ObString &column_name = qualified_name_in_aggr.at(j).col_name_; - if (!has_exist_in_array(columns_in_aggrs, column_name)) { - if (OB_FAIL(columns_in_aggrs.push_back(column_name))) { - LOG_WARN("fail to push_back column_name", K(column_name), K(ret)); - } - } - } - } - } - } - - //pivot for - if (OB_SUCC(ret)) { - if (OB_FAIL(resolve_transpose_columns(*transpose_node.children_[1], - transpose_item.for_columns_))) { - LOG_WARN("fail to resolve_transpose_columns", K(ret)); - } - } - - //pivot in - if (OB_SUCC(ret)) { - const ParseNode &in_node = *transpose_node.children_[2]; - if (OB_UNLIKELY(in_node.type_ != T_PIVOT_IN_LIST) - || OB_UNLIKELY(in_node.num_child_ <= 0) - || OB_ISNULL(in_node.children_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("in_node is unexpected", K(in_node.type_), K(in_node.num_child_), - KP(in_node.children_), K(ret)); - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < in_node.num_child_; ++i) { - const ParseNode *column_node = in_node.children_[i]; - const ParseNode *alias_node = NULL; - TransposeItem::InPair in_pair; - if (OB_ISNULL(column_node) - || OB_UNLIKELY(column_node->type_ != T_PIVOT_IN) - || OB_UNLIKELY(column_node->num_child_ != 2) - || OB_ISNULL(column_node->children_) - || OB_ISNULL(column_node->children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("column_node is unexpected", KP(column_node), K(ret)); - } else if (OB_FAIL(resolve_const_exprs(*column_node->children_[0], - in_pair.exprs_))) { - LOG_WARN("fail to resolve_const_exprs", K(ret)); - } else if (OB_UNLIKELY(in_pair.exprs_.count() != transpose_item.for_columns_.count())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("in expr number is equal for columns", K(in_pair.exprs_), - K(transpose_item.for_columns_), K(ret)); - } else if (NULL != (alias_node = column_node->children_[1])) { - if (OB_UNLIKELY(alias_node->str_len_ > OB_MAX_COLUMN_NAME_LENGTH)) { - ret = OB_ERR_TOO_LONG_IDENT; - LOG_WARN("alias name for pivot is too long", K(ret), - K(ObString(alias_node->str_len_, alias_node->str_value_))); - } else { - in_pair.pivot_expr_alias_.assign_ptr(alias_node->str_value_, alias_node->str_len_); - } - } - if (OB_SUCC(ret) && OB_FAIL(transpose_item.in_pairs_.push_back(in_pair))) { - LOG_WARN("fail to push_back in_pair", K(in_pair), K(ret)); - } - }//end of for in node - } - } - - //alias - if (OB_SUCC(ret)) { - const ParseNode &alias = *transpose_node.children_[3]; - if (alias.str_len_ > 0 && alias.str_value_ != NULL) { - transpose_item.alias_name_.assign_ptr(alias.str_value_, alias.str_len_); - } - } - } else { - transpose_item.set_unpivot(); - transpose_item.set_include_nulls(2 == transpose_node.value_); - - //unpivot column - if (OB_FAIL(resolve_transpose_columns(*transpose_node.children_[0], - transpose_item.unpivot_columns_))) { - LOG_WARN("fail to resolve_transpose_columns", K(ret)); - - //unpivot for - } else if (OB_FAIL(resolve_transpose_columns(*transpose_node.children_[1], - transpose_item.for_columns_))) { - LOG_WARN("fail to resolve_transpose_columns", K(ret)); - - //unpivot in - } else { - const ParseNode &in_node = *transpose_node.children_[2]; - if (OB_UNLIKELY(in_node.type_ != T_UNPIVOT_IN_LIST) - || OB_UNLIKELY(in_node.num_child_ <= 0) - || OB_ISNULL(in_node.children_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("in_node is unexpected", K(in_node.type_), K(in_node.num_child_), - KP(in_node.children_), K(ret)); - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < in_node.num_child_; ++i) { - const ParseNode *column_node = in_node.children_[i]; - TransposeItem::InPair in_pair; - if (OB_ISNULL(column_node) - || OB_UNLIKELY(column_node->type_ != T_UNPIVOT_IN) - || OB_UNLIKELY(column_node->num_child_ != 2) - || OB_ISNULL(column_node->children_) - || OB_ISNULL(column_node->children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("column_node is unexpectedl", KP(column_node), K(ret)); - } else if (OB_FAIL(resolve_transpose_columns(*column_node->children_[0], - in_pair.column_names_))) { - LOG_WARN("fail to resolve_transpose_columns", K(ret)); - } else if (OB_UNLIKELY(in_pair.column_names_.count() - != transpose_item.unpivot_columns_.count())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unpivot column count is not match for in column count", K(transpose_item), - K(in_pair), K(ret)); - } else if (NULL != column_node->children_[1]) { - if (OB_FAIL(resolve_const_exprs(*column_node->children_[1], in_pair.exprs_))) { - LOG_WARN("fail to resolve_const_exprs", K(ret)); - } else if (OB_UNLIKELY(in_pair.exprs_.count() != transpose_item.for_columns_.count())){ - ret = OB_ERR_UNEXPECTED; - LOG_WARN("in column count is not match in literal count", K(transpose_item), - K(in_pair), K(ret)); - } else if (OB_FAIL(transpose_item.in_pairs_.push_back(in_pair))) { - LOG_WARN("fail to push_back in_pair", K(in_pair), K(ret)); - } - } else if (OB_FAIL(transpose_item.in_pairs_.push_back(in_pair))) { - LOG_WARN("fail to push_back in_pair", K(in_pair), K(ret)); - } - }//end of for in node - } - }//end of in - - //alias - if (OB_SUCC(ret)) { - const ParseNode &alias = *transpose_node.children_[3]; - if (alias.str_len_ > 0 && alias.str_value_ != NULL) { - transpose_item.alias_name_.assign_ptr(alias.str_value_, alias.str_len_); - } - } - } - LOG_DEBUG("finish resolve_transpose_clause", K(transpose_item), K(columns_in_aggrs), K(ret)); - return ret; -} - -int ObDMLResolver::resolve_transpose_table(const ParseNode *transpose_node, +int ObDMLResolver::resolve_transpose_table( + const ParseNode &parse_tree, TableItem *&table_item) { int ret = OB_SUCCESS; - void *ptr = NULL; - if (transpose_node == NULL) { - //do nothing - } else if (OB_ISNULL(params_.expr_factory_)) { + ObTransposeResolver transpose_resolver(this); + if (OB_FAIL(transpose_resolver.resolve(parse_tree))) { + LOG_WARN("failed to resolve", K(ret)); + } else if (OB_ISNULL(table_item = transpose_resolver.get_table_item())) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("expr_factory_ is null", K(ret)); - } else if (OB_ISNULL(ptr = params_.expr_factory_->get_allocator().alloc(sizeof(TransposeItem)))) { - ret = common::OB_ALLOCATE_MEMORY_FAILED; - LOG_ERROR("no more memory to create TransposeItem"); - } else { - TransposeItem *transpose_item = new(ptr) TransposeItem(); - TableItem *orig_table_item = table_item; - table_item = NULL; - ObSEArray columns_in_aggrs; - ObSqlString transpose_def; - if (OB_ISNULL(orig_table_item)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("table_item or stmt is unexpected", KP(orig_table_item), K(ret)); - } else if (OB_FAIL(column_namespace_checker_.add_reference_table(orig_table_item))) { - LOG_WARN("add reference table to namespace checker failed", K(ret)); - } else if (OB_FAIL(resolve_transpose_clause(*transpose_node, - *transpose_item, - columns_in_aggrs))) { - LOG_WARN("resolve transpose clause failed", K(ret)); - } else if (OB_FAIL(get_transpose_target_sql(columns_in_aggrs, - *orig_table_item, - *transpose_item, - transpose_def))) { - LOG_WARN("fail to get_transpose_target_sql", KPC(orig_table_item), K(ret)); - } else if (OB_FAIL(remove_orig_table_item(*orig_table_item))) { - LOG_WARN("remove_orig_table_item failed", K(ret)); - } else if (OB_FAIL(expand_transpose(transpose_def, *transpose_item, table_item))) { - LOG_WARN("expand_transpose failed", K(ret)); - } - } - return ret; -} - -int ObDMLResolver::expand_transpose(const ObSqlString &transpose_def, - TransposeItem &transpose_item, TableItem *&table_item) -{ - int ret = OB_SUCCESS; - ObParser parser(*params_.allocator_, session_info_->get_sql_mode()); - ParseResult transpose_result; - - params_.external_param_info_.need_clear_ = true; - DEFER(params_.external_param_info_.need_clear_ = false); - - if (OB_FAIL(parser.parse(transpose_def.string(), transpose_result))) { - LOG_WARN("parse view defination failed", K(transpose_def.string()), K(ret)); - } else if (OB_ISNULL(transpose_result.result_tree_) - || OB_ISNULL(transpose_result.result_tree_->children_) - || OB_UNLIKELY(transpose_result.result_tree_->num_child_ < 1) - || OB_ISNULL(transpose_result.result_tree_->children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("transpose_result.result_tree_ is null", K(transpose_result.result_tree_), K(ret)); - } else { - //use select resolver - ObSelectResolver select_resolver(params_); - //from子查询和当前查询属于平级,因此current level和当前保持一致 - select_resolver.set_current_level(current_level_); - select_resolver.set_is_sub_stmt(true); - select_resolver.set_parent_namespace_resolver(parent_namespace_resolver_); - select_resolver.set_current_view_level(current_view_level_); - select_resolver.set_transpose_item(&transpose_item); - ParseNode tmp_node; - tmp_node.type_ = T_IDENT; - tmp_node.str_len_ = transpose_item.alias_name_.length(); - tmp_node.str_value_ = transpose_item.alias_name_.ptr(); - if (OB_FAIL(add_cte_table_to_children(select_resolver))) { - LOG_WARN("add_cte_table_to_children failed", K(ret)); - } else if (OB_FAIL(do_resolve_generate_table(*transpose_result.result_tree_->children_[0], - &tmp_node, - select_resolver, - table_item))) { - LOG_WARN("do_resolve_generate_table failed", K(ret)); - } else if (OB_FAIL(mark_unpivot_table(transpose_item, table_item))) { - LOG_WARN("fail to mark_unpivot_table", KPC(table_item), K(ret)); - } - LOG_DEBUG("finish expand_transpose", K(transpose_def), K(transpose_item), KPC(table_item)); - } - return ret; -} - -int ObDMLResolver::mark_unpivot_table(TransposeItem &transpose_item, TableItem *table_item) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(table_item) - || OB_UNLIKELY(!table_item->is_generated_table() && !table_item->is_temp_table()) - || OB_ISNULL(table_item->ref_query_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("table_item or unexpected", KPC(table_item), K(ret)); - } else if (transpose_item.is_unpivot() && transpose_item.need_use_unpivot_op()) { - ObSelectStmt &select_stmt = *table_item->ref_query_; - for (int64_t i = select_stmt.get_unpivot_info().get_output_column_count(); - i < select_stmt.get_select_item_size(); - i++) { - SelectItem &item = select_stmt.get_select_item(i); - item.is_unpivot_mocked_column_ = true; - } - } - return ret; -} - -int get_column_item_idx_by_name(ObIArray &array, const ObString &var, int64_t &idx) -{ - int ret = OB_SUCCESS; - idx = OB_INVALID_INDEX; - const int64_t num = array.count(); - for (int64_t i = 0; i < num; i++) { - if (var == array.at(i).column_name_) { - idx = i; - break; - } - } - return ret; -} - -int ObDMLResolver::get_transpose_target_sql(const ObIArray &columns_in_aggrs, - TableItem &table_item, TransposeItem &transpose_item, ObSqlString &sql) -{ - int ret = OB_SUCCESS; - sql.reuse(); - //1.get columns - ObSEArray column_items; - if (table_item.is_basic_table() || table_item.is_fake_cte_table() || table_item.is_link_table()) { - if (OB_FAIL(resolve_all_basic_table_columns(table_item, false, &column_items))) { - LOG_WARN("resolve all basic table columns failed", K(ret)); - } - } else if (table_item.is_generated_table() || table_item.is_temp_table()) { - if (OB_FAIL(resolve_all_generated_table_columns(table_item, column_items))) { - LOG_WARN("resolve all generated table columns failed", K(ret)); - } - } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("not support this table", K(table_item), K(ret)); - } - - int64_t idx = OB_INVALID_INDEX; - if (transpose_item.is_pivot()) { - //2.check and get groupby column - for (int64_t i = 0; OB_SUCC(ret) && i < columns_in_aggrs.count(); ++i) { - const ObString &column_name = columns_in_aggrs.at(i); - if (OB_FAIL(get_column_item_idx_by_name(column_items, column_name, idx))) { - LOG_WARN("fail to get_column_item_idx_by_name", K(column_name), K(ret)); - } else if (idx >= 0) { - if (OB_FAIL(column_items.remove(idx))) { - LOG_WARN("fail to remove column_item", K(idx), K(ret)); - } - } - } - - for (int64_t i = 0; OB_SUCC(ret) && i < transpose_item.for_columns_.count(); ++i) { - ObString &for_column = transpose_item.for_columns_.at(i); - if (OB_FAIL(get_column_item_idx_by_name(column_items, for_column, idx))) { - LOG_WARN("fail to get_column_item_idx_by_name", K(for_column), K(ret)); - } else if (idx >= 0) { - if (OB_FAIL(column_items.remove(idx))) { - LOG_WARN("fail to remove column_item", K(idx), K(ret)); - } - } - } - - if (OB_SUCC(ret)) { - transpose_item.old_column_count_ = column_items.count(); - if (OB_FAIL(get_target_sql_for_pivot(column_items, table_item, transpose_item, sql))) { - LOG_WARN("fail to get_target_sql_for_pivot", K(ret)); - } - } - LOG_DEBUG("finish get_transpose_target_sql", K(ret), K(sql), K(transpose_item)); - transpose_item.reset();//no need aggr/for/in expr, reset here - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < transpose_item.in_pairs_.count(); ++i) { - const common::ObIArray &in_columns = transpose_item.in_pairs_.at(i).column_names_; - for (int64_t j = 0; OB_SUCC(ret) && j < in_columns.count(); ++j) { - const ObString &column_name = in_columns.at(j); - if (OB_FAIL(get_column_item_idx_by_name(column_items, column_name, idx))) { - LOG_WARN("fail to get_column_item_idx_by_name", K(column_name), K(ret)); - } else if (idx >= 0) { - if (OB_FAIL(column_items.remove(idx))) { - LOG_WARN("fail to remove column_item", K(idx), K(ret)); - } - } - } - } - - if (OB_SUCC(ret)) { - transpose_item.old_column_count_ = column_items.count(); - if (OB_FAIL(get_target_sql_for_unpivot(column_items, table_item, transpose_item, sql))) { - LOG_WARN("fail to get_target_sql_for_unpivot", K(ret)); - } - } - LOG_DEBUG("finish get_transpose_target_sql", K(ret), K(sql), K(transpose_item)); - } - return ret; -} - -//for example -// -//t1(c1, c2, c3, c4) -// -//from_list(basic_table): -//t1 -//pivot ( -// sum(c1) as sum, -// max(c1) -// for (c2, c3) -// in ((1, 1) as "11", -// (2, 2) -// ) -//) -//t11 -// -//from_list(generated_table): -//(select * from t1) -//pivot ( -// sum(c1) as sum, -// max(c1) -// for (c2, c3) -// in ((1, 1) as "11", -// (2, 2) -// ) -//) t11 -// -//from_list(target_table): -//(select -// c4, -// sum(case when (c2, c3) in ((1, 1)) then c1 end) as "11_sum", -// max(case when (c2, c3) in ((1, 1)) then c1 end) as "11", -// sum(case when (c2, c3) in ((2, 2)) then c1 end) as "2_2_sum", -// max(case when (c2, c3) in ((2, 2)) then c1 end) as "2_2" -//from t1 -//group by c4 -//) t11 -int ObDMLResolver::get_target_sql_for_pivot(const ObIArray &column_items, - TableItem &table_item, TransposeItem &transpose_item, ObSqlString &sql) -{ - int ret = OB_SUCCESS; - sql.reuse(); - if (transpose_item.is_pivot()) { - if (!transpose_item.alias_name_.empty()) { - if (OB_FAIL(sql.append("SELECT * FROM ( "))) { - LOG_WARN("fail to append_fmt",K(ret)); - } - } - - if (OB_FAIL(ret)) { - } else if (OB_FAIL(sql.append("SELECT"))) { - LOG_WARN("fail to append_fmt",K(ret)); - } else if ((table_item.is_generated_table() || table_item.is_temp_table()) && table_item.ref_query_ != NULL) { - /* Now, do not print use_hash_aggregation hint for pivot. */ - } - - if (!column_items.empty()) { - for (int64_t i = 0; OB_SUCC(ret) && i < column_items.count(); ++i) { - const ObString &column_name = column_items.at(i).column_name_; - if (OB_FAIL(sql.append_fmt(" \"%.*s\",", column_name.length(), column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(column_name), K(ret)); - } - } - } - const int64_t DISTINCT_LENGTH = strlen("DISTINCT"); - if (OB_SUCC(ret)) { - SMART_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf) { - MEMSET(expr_str_buf, 0 , sizeof(expr_str_buf)); - for (int64_t i = 0; OB_SUCC(ret) && i < transpose_item.in_pairs_.count(); ++i) { - const TransposeItem::InPair &in_pair = transpose_item.in_pairs_.at(i); - - for (int64_t j = 0; OB_SUCC(ret) && j < transpose_item.aggr_pairs_.count(); ++j) { - const TransposeItem::AggrPair &aggr_pair = transpose_item.aggr_pairs_.at(j); - const char *format_str = - ((static_cast(aggr_pair.expr_))->is_param_distinct() - ? " %s(DISTINCT CASE WHEN (" - : " %s(CASE WHEN ("); - if (OB_FAIL(sql.append_fmt(format_str, - ob_aggr_func_str(aggr_pair.expr_->get_expr_type())))) { - LOG_WARN("fail to append_fmt", K(aggr_pair.expr_->get_expr_type()), K(ret)); - } - for (int64_t k = 0; OB_SUCC(ret) && k < transpose_item.for_columns_.count(); ++k) { - const ObString &column_name = transpose_item.for_columns_.at(k); - if (OB_FAIL(sql.append_fmt("\"%.*s\",", column_name.length(), column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(column_name), K(ret)); - } - } - - if (OB_FAIL(ret)){ - } else if (OB_FAIL(sql.set_length(sql.length() - 1))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } else if (OB_FAIL(sql.append(") in (("))) { - LOG_WARN("fail to append", K(ret)); - } - - for (int64_t k = 0; OB_SUCC(ret) && k < in_pair.exprs_.count(); ++k) { - ObRawExpr *expr = in_pair.exprs_.at(k); - int64_t pos = 0; - ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, - schema_checker_->get_schema_guard(), - TZ_INFO(params_.session_info_)); - if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { - LOG_WARN("print expr definition failed", KPC(expr), K(ret)); - } else if (OB_FAIL(sql.append_fmt("%.*s,", static_cast(pos), expr_str_buf))) { - LOG_WARN("fail to append_fmt", K(expr_str_buf), K(ret)); - } - } - - if (OB_FAIL(ret)){ - } else if (OB_FAIL(sql.set_length(sql.length() - 1))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } else if (OB_FAIL(sql.append("))"))) { - LOG_WARN("fail to append", K(ret)); - } - - int64_t pos = 0; - if (OB_FAIL(ret)) { - } else if (0 == static_cast(aggr_pair.expr_)->get_param_count() - && T_FUN_COUNT == aggr_pair.expr_->get_expr_type()) { - // for count(*), just use 0 as then value - if (OB_FAIL(sql.append_fmt(" THEN 0 END) AS \""))) { - LOG_WARN("fail to append_fmt", K(aggr_pair.alias_name_), K(ret)); - } - } else { - int32_t expr_name_length = strlen(ob_aggr_func_str(aggr_pair.expr_->get_expr_type())) + 1; - if ((static_cast(aggr_pair.expr_))->is_param_distinct()) { - expr_name_length += DISTINCT_LENGTH; - } - ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, - schema_checker_->get_schema_guard(), - TZ_INFO(params_.session_info_)); - if (OB_FAIL(expr_printer.do_print(aggr_pair.expr_, T_NONE_SCOPE, true))) { - LOG_WARN("print expr definition failed", KPC(aggr_pair.expr_), K(ret)); - } else if (OB_FAIL(sql.append_fmt(" THEN %.*s END) AS \"", - static_cast(pos - expr_name_length - 1), - expr_str_buf + expr_name_length))) { - LOG_WARN("fail to append_fmt", K(aggr_pair.alias_name_), K(ret)); - } - } - if (OB_SUCC(ret)) { - ObString tmp(pos, expr_str_buf); - int64_t sql_length = sql.length(); - if (in_pair.pivot_expr_alias_.empty()) { - for (int64_t k = 0; OB_SUCC(ret) && k < in_pair.exprs_.count(); ++k) { - ObRawExpr *expr = in_pair.exprs_.at(k); - int64_t pos = 0; - ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, - schema_checker_->get_schema_guard(), - TZ_INFO(params_.session_info_)); - if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { - LOG_WARN("print expr definition failed", KPC(expr), K(ret)); - } else if (OB_FAIL(sql.append_fmt("%.*s_", static_cast(pos), - expr_str_buf))) { - LOG_WARN("fail to append_fmt", K(expr_str_buf), K(ret)); - } - } - if (OB_FAIL(ret)){ - } else if (OB_FAIL(sql.set_length(sql.length() - 1))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } - } else { - if (OB_FAIL(sql.append_fmt("%.*s", in_pair.pivot_expr_alias_.length(), - in_pair.pivot_expr_alias_.ptr()))) { - LOG_WARN("fail to append_fmt", K(in_pair.pivot_expr_alias_), K(ret)); - } - } - if (OB_FAIL(ret)){ - } else if (! aggr_pair.alias_name_.empty()) { - if (OB_FAIL(sql.append_fmt("_%.*s", aggr_pair.alias_name_.length(), - aggr_pair.alias_name_.ptr()))) { - LOG_WARN("fail to append_fmt", K(aggr_pair.alias_name_), K(ret)); - } - } - if (OB_SUCC(ret)) { - sql.set_length(MIN(sql.length(), sql_length + OB_MAX_COLUMN_NAME_LENGTH)); - if (OB_FAIL(sql.append("\","))) { - LOG_WARN("fail to append", K(ret)); - } - } - } - }//end of aggr - }//end of in - if (OB_FAIL(ret)){ - } else if (OB_FAIL(sql.set_length(sql.length() - 1))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } else if (OB_FAIL(format_from_subquery(transpose_item.alias_name_, - table_item, expr_str_buf, sql))) { - LOG_WARN("fail to format_from_subquery", K(table_item), K(ret)); - } - - if (OB_FAIL(ret)){ - } else if (!column_items.empty()) { - if (OB_FAIL(sql.append(" GROUP BY"))) { - LOG_WARN("fail to append", K(ret)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < column_items.count(); ++i) { - const ObString &column_name = column_items.at(i).column_name_; - if (OB_FAIL(sql.append_fmt(" \"%.*s\",", column_name.length(), column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(column_name), K(ret)); - } - } - if (OB_FAIL(ret)){ - } else if (OB_FAIL(sql.set_length(sql.length() - 1))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } - } - - if (OB_SUCC(ret)){ - if (!transpose_item.alias_name_.empty()) { - if (OB_FAIL(sql.append_fmt(" ) %.*s", transpose_item.alias_name_.length(), - transpose_item.alias_name_.ptr()))) { - LOG_WARN("fail to append", K(ret)); - } - } - } - }//end SMART_VAR - } - } - return ret; -} - -int ObDMLResolver::format_from_subquery(const ObString &unpivot_alias_name, - TableItem &table_item, char *expr_str_buf, ObSqlString &sql) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(params_.query_ctx_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null pointer", K(ret)); - } else if (table_item.is_basic_table() || table_item.is_link_table()) { - if (OB_FAIL(sql.append_fmt(" FROM \"%.*s\".\"%.*s\"", table_item.database_name_.length(), - table_item.database_name_.ptr(), - table_item.table_name_.length(), - table_item.table_name_.ptr()))) { - LOG_WARN("fail to append_fmt", K(table_item.table_name_), K(ret)); - } else if (OB_FAIL(get_partition_for_transpose(table_item, sql))) { - LOG_WARN("fail to get_partition_for_transpose", K(table_item), K(ret)); - } else if (!table_item.alias_name_.empty() - && table_item.alias_name_ != table_item.table_name_) { - if (OB_FAIL(sql.append_fmt(" %.*s", table_item.alias_name_.length(), - table_item.alias_name_.ptr()))) { - LOG_WARN("fail to append_fmt", K(table_item.alias_name_), K(ret)); - } - } else if (!unpivot_alias_name.empty()) { - if (OB_FAIL(sql.append_fmt(" %.*s", unpivot_alias_name.length(), - unpivot_alias_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(unpivot_alias_name), K(ret)); - } - } - } else { - int64_t pos = 0; - ObObjPrintParams obj_print_params(params_.query_ctx_->get_timezone_info()); - obj_print_params.print_origin_stmt_ = true; - ObSelectStmtPrinter stmt_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, - static_cast(table_item.ref_query_), - schema_checker_->get_schema_guard(), - obj_print_params, true); - if (OB_FAIL(stmt_printer.do_print())) { - LOG_WARN("fail to print generated table", K(ret)); - } else if (OB_FAIL(sql.append_fmt(" FROM (%.*s)", static_cast(pos), expr_str_buf))) { - LOG_WARN("fail to append_fmt", K(ret)); - } else if (table_item.cte_type_ == TableItem::NOT_CTE - && !table_item.table_name_.empty()) { - if (OB_FAIL(sql.append_fmt(" %.*s", table_item.table_name_.length(), - table_item.table_name_.ptr()))) { - LOG_WARN("fail to append_fmt", K(ret)); - } - } else if (!unpivot_alias_name.empty()) { - if (OB_FAIL(sql.append_fmt(" %.*s", unpivot_alias_name.length(), - unpivot_alias_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(unpivot_alias_name), K(ret)); - } - } - } - return ret; -} - -int ObDMLResolver::get_partition_for_transpose(TableItem &table_item, ObSqlString &sql) -{ - int ret = OB_SUCCESS; - if (table_item.access_all_part()) { - /* do nothing */ - } else if (OB_FAIL(sql.append(" PARTITION ("))) { - LOG_WARN("fail to append", K(ret)); - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < table_item.part_names_.count(); ++i) { - ObString part_names_tmp(table_item.part_names_.at(i)); - if (OB_FAIL(sql.append_fmt("%.*s, ", part_names_tmp.length(), part_names_tmp.ptr()))) { - LOG_WARN("fail to append", K(ret)); - } - } - if (OB_FAIL(ret)) { - } else if (OB_FAIL(sql.set_length(sql.length() - 2))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } else if (OB_FAIL(sql.append(")"))) { - LOG_WARN("fail to append", K(ret)); - } - } - return ret; -} - -//for example -// -//t1(c1, c2, c3, c4) -// -//from_list(basic_table): -//t1 -//unpivot exclude nulls ( -//(sal1, sal2) -//for (deptno1, deptno2) -//in ((c2, c3), -// (c3, c4) as ('c33', 'c44') -//) -//t11 -// -//from_list(generated_table): -//(select * from t1) -//unpivot exclude nulls ( -//(sal1, sal2) -//for (deptno1, deptno2) -//in ((c2, c3), -// (c3, c4) as ('c33', 'c44') -//) -//) t11 -// -//from_list(target_table): -// select * from -// (select c1, 'c2_c3' as deptno1, 'c2_c3' as deptno2, c2 as sal1, c3 as sal2 , -// 'c33' as deptno1, 'c44' as deptno2, c3 as sal1, c4 as sal2 -// from pivoted_emp2 -// where (c2 is not null or c3 is not null) -// and (c3 is not null or c4 is not null) -// ) -int ObDMLResolver::get_target_sql_for_unpivot(const ObIArray &column_items, - TableItem &table_item, TransposeItem &transpose_item, ObSqlString &sql) -{ - int ret = OB_SUCCESS; - sql.reuse(); - if (transpose_item.is_unpivot()) { - if (OB_FAIL(sql.append("SELECT /*+NO_REWRITE UNPIVOT*/* FROM (SELECT /*+NO_REWRITE*/"))) { - LOG_WARN("fail to append",K(ret)); - } else if (!column_items.empty()) { - for (int64_t i = 0; OB_SUCC(ret) && i < column_items.count(); ++i) { - const ObString &column_name = column_items.at(i).column_name_; - if (OB_FAIL(sql.append_fmt(" \"%.*s\",", column_name.length(), column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(column_name), K(ret)); - } - } - } - - if (OB_SUCC(ret)) { - SMART_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf) { - MEMSET(expr_str_buf, 0, sizeof(expr_str_buf)); - for (int64_t i = 0; OB_SUCC(ret) && i < transpose_item.in_pairs_.count(); ++i) { - const TransposeItem::InPair &in_pair = transpose_item.in_pairs_.at(i); - for (int64_t j = 0; OB_SUCC(ret) && j < transpose_item.for_columns_.count(); ++j) { - const ObString &for_column_name = transpose_item.for_columns_.at(j); - - if (in_pair.exprs_.empty()) { - if (OB_FAIL(sql.append(" '"))) { - LOG_WARN("fail to append_fmt",K(ret)); - } - //TODO::use upper - for (int64_t k = 0; OB_SUCC(ret) && k < in_pair.column_names_.count(); ++k) { - const ObString &column_name = in_pair.column_names_.at(k); - if (OB_FAIL(sql.append_fmt("%.*s_", column_name.length(), column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(column_name), K(ret)); - } - } - - if (OB_FAIL(ret)){ - } else if (OB_FAIL(sql.set_length(sql.length() - 1))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } else if (0 == i) { - if (OB_FAIL(sql.append_fmt("' AS \"%.*s\",", - for_column_name.length(), for_column_name.ptr()))) { - LOG_WARN("fail to append", K(for_column_name), K(ret)); - } - } else if (OB_FAIL(sql.append_fmt("' AS \"%ld_%.*s\",", - i, for_column_name.length(), for_column_name.ptr()))) { - LOG_WARN("fail to append", K(for_column_name), K(ret)); - } - } else { - ObRawExpr *expr = in_pair.exprs_.at(j); - int64_t pos = 0; - ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, - schema_checker_->get_schema_guard(), TZ_INFO(params_.session_info_)); - if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) { - LOG_WARN("print expr definition failed", KPC(expr), K(ret)); - } else if (0 == i) { - if (OB_FAIL(sql.append_fmt(" %.*s AS \"%.*s\",", - static_cast(pos), expr_str_buf, - for_column_name.length(), for_column_name.ptr()))) { - LOG_WARN("fail to append", K(for_column_name), K(ret)); - } - } else if (OB_FAIL(sql.append_fmt(" %.*s AS \"%ld_%.*s\",", - static_cast(pos), expr_str_buf, - i, for_column_name.length(), for_column_name.ptr()))) { - LOG_WARN("fail to append", K(for_column_name), K(ret)); - } - } - } - - for (int64_t j = 0; OB_SUCC(ret) && j < in_pair.column_names_.count(); ++j) { - const ObString &in_column_name = in_pair.column_names_.at(j); - const ObString &unpivot_column_name = transpose_item.unpivot_columns_.at(j); - if (0 == i) { - if (OB_FAIL(sql.append_fmt(" \"%.*s\" AS \"%.*s\",", - in_column_name.length(), in_column_name.ptr(), - unpivot_column_name.length(), unpivot_column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(in_column_name), K(unpivot_column_name), K(ret)); - } - } else if (OB_FAIL(sql.append_fmt(" \"%.*s\" AS \"%ld_%.*s\",", - in_column_name.length(), in_column_name.ptr(), - i, unpivot_column_name.length(), unpivot_column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(in_column_name), K(unpivot_column_name), K(ret)); - } - } - } - - if (OB_FAIL(ret)){ - } else if (OB_FAIL(sql.set_length(sql.length() - 1))) { - LOG_WARN("fail to set_length", K(sql.length()), K(ret)); - } else if (OB_FAIL(format_from_subquery(transpose_item.alias_name_, - table_item, expr_str_buf, sql))) { - LOG_WARN("fail to format_from_subquery", K(table_item), K(ret)); - } else if (transpose_item.is_exclude_null()) { - if (OB_FAIL(sql.append(" WHERE"))) { - LOG_WARN("fail to append", K(ret)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < transpose_item.in_pairs_.count(); ++i) { - const TransposeItem::InPair &in_pair = transpose_item.in_pairs_.at(i); - const char *format_str = (i != 0 ? " OR (" : " ("); - if (OB_FAIL(sql.append(format_str))) { - LOG_WARN("fail to append", K(ret)); - } - for (int64_t j = 0; OB_SUCC(ret) && j < in_pair.column_names_.count(); ++j) { - const ObString &column_name = in_pair.column_names_.at(j); - const char *format_str = (j != 0 ? " OR \"%.*s\" IS NOT NULL" : " \"%.*s\" IS NOT NULL"); - if (OB_FAIL(sql.append_fmt(format_str, column_name.length(), column_name.ptr()))) { - LOG_WARN("fail to append_fmt", K(column_name), K(ret)); - } - } - if (OB_SUCC(ret) && OB_FAIL(sql.append(")"))) { - LOG_WARN("fail to append", K(ret)); - } - } - } - - if (OB_SUCC(ret)) { - if (OB_FAIL(sql.append(")"))) { - LOG_WARN("fail to append", K(ret)); - } else if (!transpose_item.alias_name_.empty()) { - if (OB_FAIL(sql.append_fmt(" %.*s", transpose_item.alias_name_.length(), - transpose_item.alias_name_.ptr()))) { - LOG_WARN("fail to append", K(ret)); - } - } - } - } - } - } - return ret; -} - - -int ObDMLResolver::remove_orig_table_item(TableItem &table_item) -{ - int ret = OB_SUCCESS; - //need remove last saved table item - ObDMLStmt *stmt = get_stmt(); - if (OB_ISNULL(stmt)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("stmt is unexpected", KP(stmt), K(ret)); - } else if (OB_FAIL(column_namespace_checker_.remove_reference_table(table_item.table_id_))) { - LOG_WARN("failed to remove_reference_table", K(ret)); - } else if (OB_FAIL(stmt->remove_table_item(&table_item))) { - LOG_WARN("failed to remove target table items", K(ret)); - } else if (OB_FAIL(stmt->remove_column_item(table_item.table_id_))) { - LOG_WARN("failed to remove column items.", K(ret)); - } else if (OB_FAIL(stmt->remove_part_expr_items(table_item.table_id_))) { - LOG_WARN("failed to remove part expr item", K(ret)); - } else if (OB_FAIL(stmt->rebuild_tables_hash())) { - LOG_WARN("rebuild table hash failed", K(ret)); + LOG_WARN("failed to resolve", K(ret)); } return ret; } @@ -14158,13 +13179,13 @@ int ObDMLResolver::generate_check_constraint_exprs(const TableItem *table_item, } else if (resolve_check_for_optimizer) { int64_t check_flag = 0; if ((*iter)->get_enable_flag()) { - check_flag |= ObDMLStmt::CheckConstraintFlag::IS_ENABLE_CHECK; + check_flag |= CheckConstraintFlag::IS_ENABLE_CHECK; } if ((*iter)->is_validated()) { - check_flag |= ObDMLStmt::CheckConstraintFlag::IS_VALIDATE_CHECK; + check_flag |= CheckConstraintFlag::IS_VALIDATE_CHECK; } if ((*iter)->get_rely_flag()) { - check_flag |= ObDMLStmt::CheckConstraintFlag::IS_RELY_CHECK; + check_flag |= CheckConstraintFlag::IS_RELY_CHECK; } if (OB_FAIL(check_flags->push_back(check_flag))) { LOG_WARN("failed to push back", K(ret)); @@ -18808,8 +17829,6 @@ int ObDMLResolver::resolve_cte_table( table_item->cte_type_ = CTE_table_item->cte_type_; if (OB_FAIL(dml_stmt->add_table_item(session_info_, table_item))) { LOG_WARN("add table item failed", K(ret)); - } else if (OB_FAIL(resolve_transpose_table(transpose_node, table_item))) { - LOG_WARN("resolve_transpose_table failed", K(ret)); } } cte_ctx_.set_current_cte_table_name(old_cte_table_name); diff --git a/src/sql/resolver/dml/ob_dml_resolver.h b/src/sql/resolver/dml/ob_dml_resolver.h index edc49b4116..748bde091b 100644 --- a/src/sql/resolver/dml/ob_dml_resolver.h +++ b/src/sql/resolver/dml/ob_dml_resolver.h @@ -189,6 +189,7 @@ public: inline void set_parent_namespace_resolver(ObDMLResolver *parent_namespace_resolver) { parent_namespace_resolver_ = parent_namespace_resolver; } inline ObDMLResolver *get_parent_namespace_resolver() { return parent_namespace_resolver_; } + inline ObColumnNamespaceChecker& get_column_namespace_checker() { return column_namespace_checker_; } virtual int resolve_column_ref_for_subquery(const ObQualifiedName &q_name, ObRawExpr *&real_ref_expr); int resolve_generated_column_expr(const common::ObString &expr_str, const TableItem &table_item, @@ -403,6 +404,11 @@ protected: int generate_subschema_id(ObColumnRefRawExpr &col_expr); public: virtual int resolve_table(const ParseNode &parse_tree, TableItem *&table_item); + int resolve_all_basic_table_columns(const TableItem &table_item, + bool included_hidden, + common::ObIArray *column_items); + int resolve_all_generated_table_columns(const TableItem &table_item, + common::ObIArray &column_items); protected: virtual int resolve_generate_table(const ParseNode &table_node, const ParseNode *alias_node, @@ -443,11 +449,6 @@ protected: const common::ObString &synonym_db_name, TableItem *&table_item, bool is_reverse_link); - int resolve_all_basic_table_columns(const TableItem &table_item, - bool included_hidden, - common::ObIArray *column_items); - int resolve_all_generated_table_columns(const TableItem &table_item, - common::ObIArray &column_items); int resolve_columns_for_partition_expr(ObRawExpr *&expr, ObIArray &columns, const TableItem &table_item, bool is_hidden); @@ -459,8 +460,10 @@ protected: int resolve_limit_clause(const ParseNode *node, bool disable_offset = false); int resolve_approx_clause(const ParseNode *approx_node); int resolve_into_clause(const ParseNode *node); +public: int resolve_hints(const ParseNode *node); int resolve_outline_data_hints(); +protected: const ParseNode *get_outline_data_hint_node(); int inner_resolve_hints(const ParseNode &node, const bool filter_embedded_hint, @@ -528,25 +531,9 @@ protected: TableItem &table_item); int check_pivot_aggr_expr(ObRawExpr *expr) const; - int resolve_transpose_table(const ParseNode *transpose_node, TableItem *&table_item); - int resolve_transpose_clause(const ParseNode &transpose_node, TransposeItem &transpose_item, - ObIArray &columns_in_aggr); - int resolve_transpose_columns(const ParseNode &transpose_node, ObIArray &columns); - int resolve_const_exprs(const ParseNode &transpose_node, ObIArray &const_exprs); - int get_transpose_target_sql(const ObIArray &columns_in_aggrs, TableItem &table_item, - TransposeItem &transpose_item, ObSqlString &target_sql); - int get_target_sql_for_pivot(const ObIArray &column_items, TableItem &table_item, - TransposeItem &transpose_item, ObSqlString &target_sql); - int get_target_sql_for_unpivot(const ObIArray &column_items, TableItem &table_item, - TransposeItem &transpose_item, ObSqlString &target_sql); - int format_from_subquery(const ObString &unpivot_alias_name, TableItem &table_item, - char *expr_str_buf, ObSqlString &target_sql); - int get_partition_for_transpose(TableItem &table_item, ObSqlString &sql); - int expand_transpose(const ObSqlString &transpose_def, TransposeItem &transpose_item, - TableItem *&table_item); - int mark_unpivot_table(TransposeItem &transpose_item, TableItem *table_item); - int remove_orig_table_item(TableItem &table_item); - +public: + int resolve_transpose_table(const ParseNode &parse_tree, TableItem *&table_item); +protected: int check_basic_column_generated(const ObColumnRefRawExpr *col_expr, ObDMLStmt *dml_stmt, bool &is_generated); diff --git a/src/sql/resolver/dml/ob_dml_stmt.cpp b/src/sql/resolver/dml/ob_dml_stmt.cpp index 22f06a4e3a..66a3066a0a 100644 --- a/src/sql/resolver/dml/ob_dml_stmt.cpp +++ b/src/sql/resolver/dml/ob_dml_stmt.cpp @@ -18,67 +18,21 @@ using namespace oceanbase::sql; using namespace oceanbase::common; using namespace oceanbase::share::schema; -int TransposeItem::InPair::assign(const TransposeItem::InPair &other) +int ObUnpivotItem::deep_copy(ObIRawExprCopier &expr_copier, + const ObUnpivotItem &other) { int ret = OB_SUCCESS; - if (this == &other) { - //do nothing - } else if (OB_FAIL(exprs_.assign(other.exprs_))) { - LOG_WARN("assign searray failed", K(other), K(ret)); - } else if (OB_FAIL(column_names_.assign(other.column_names_))) { - LOG_WARN("assign searray failed", K(other), K(ret)); - } else { - pivot_expr_alias_ = other.pivot_expr_alias_; + is_include_null_ = other.is_include_null_; + if (OB_FAIL(expr_copier.copy(other.origin_exprs_, origin_exprs_))) { + LOG_WARN("failed to copy key exprs"); + } else if (OB_FAIL(expr_copier.copy(other.label_exprs_ , label_exprs_))) { + LOG_WARN("failed to copy for exprs"); + } else if (OB_FAIL(expr_copier.copy(other.value_exprs_ , value_exprs_))) { + LOG_WARN("failed to copy val exprs"); } return ret; } -int TransposeItem::assign(const TransposeItem &other) -{ - int ret = OB_SUCCESS; - if (this == &other) { - //do nothing - } else if (OB_FAIL(for_columns_.assign(other.for_columns_))) { - LOG_WARN("assign searray failed", K(other), K(ret)); - } else if (OB_FAIL(in_pairs_.assign(other.in_pairs_))) { - LOG_WARN("assign searray failed", K(other), K(ret)); - } else if (OB_FAIL(unpivot_columns_.assign(other.unpivot_columns_))) { - LOG_WARN("assign searray failed", K(other), K(ret)); - } else { - aggr_pairs_.reset(); - old_column_count_ = other.old_column_count_; - is_unpivot_ = other.is_unpivot_; - is_incude_null_ = other.is_incude_null_; - alias_name_ = other.alias_name_; - } - return ret; -} - -int TransposeItem::deep_copy(ObIRawExprCopier &expr_copier, - const TransposeItem &other) -{ - int ret = OB_SUCCESS; - if (OB_FAIL(assign(other))) { - LOG_WARN("assign failed", K(other), K(ret)); - } - - for (int64_t i = 0; i < in_pairs_.count() && OB_SUCC(ret); ++i) { - InPair &in_pair = in_pairs_.at(i); - in_pair.exprs_.reuse(); - if (OB_FAIL(expr_copier.copy(other.in_pairs_.at(i).exprs_, - in_pair.exprs_))) { - LOG_WARN("deep copy expr failed", K(ret)); - } - } - return ret; -} - -OB_SERIALIZE_MEMBER(ObUnpivotInfo, - old_column_count_, - unpivot_column_count_, - for_column_count_, - is_include_null_); - int SemiInfo::deep_copy(ObIRawExprCopier &expr_copier, const SemiInfo &other) { int ret = OB_SUCCESS; @@ -372,7 +326,7 @@ int JoinedTable::deep_copy(ObIAllocator &allocator, return ret; } -int ObDMLStmt::PartExprItem::deep_copy(ObIRawExprCopier &expr_copier, +int PartExprItem::deep_copy(ObIRawExprCopier &expr_copier, const PartExprItem &other) { int ret = OB_SUCCESS; @@ -412,7 +366,7 @@ ObDMLStmt::ObDMLStmt(stmt::StmtType type) pseudo_column_like_exprs_(), tables_hash_(), subquery_exprs_(), - transpose_item_(NULL), + unpivot_item_(NULL), user_var_exprs_(), check_constraint_items_(), dblink_id_(OB_INVALID_ID), @@ -527,7 +481,7 @@ int ObDMLStmt::assign(const ObDMLStmt &other) is_contains_assignment_ = other.is_contains_assignment_; affected_last_insert_id_ = other.affected_last_insert_id_; has_part_key_sequence_ = other.has_part_key_sequence_; - transpose_item_ = other.transpose_item_; + unpivot_item_ = other.unpivot_item_; dblink_id_ = other.dblink_id_; is_reverse_link_ = other.is_reverse_link_; has_vec_approx_ = other.has_vec_approx_; @@ -699,14 +653,14 @@ int ObDMLStmt::deep_copy_stmt_struct(ObIAllocator &allocator, has_vec_approx_ = other.has_vec_approx_; } if (OB_SUCC(ret)) { - TransposeItem *tmp = NULL; - if (OB_FAIL(deep_copy_stmt_object(allocator, + ObUnpivotItem *tmp = NULL; + if (OB_FAIL(deep_copy_stmt_object(allocator, expr_copier, - other.transpose_item_, + other.unpivot_item_, tmp))) { - LOG_WARN("failed to deep copy transpose item", K(ret)); + LOG_WARN("failed to deep copy unpivot info", K(ret)); } else { - transpose_item_ = tmp; + unpivot_item_ = tmp; } } return ret; @@ -959,15 +913,6 @@ int ObDMLStmt::iterate_stmt_expr(ObStmtExprVisitor &visitor) } else {} } - if (NULL != transpose_item_) { - for (int64_t i = 0; i < transpose_item_->in_pairs_.count() && OB_SUCC(ret); ++i) { - TransposeItem::InPair &in_pair = const_cast(transpose_item_->in_pairs_.at(i)); - if (OB_FAIL(visitor.visit(in_pair.exprs_, SCOPE_PIVOT))) { - LOG_WARN("failed to visit in pair exprs", K(ret)); - } - } - } - if (OB_SUCC(ret) && visitor.is_recursive()) { ObSEArray subqueries; if (OB_FAIL(get_child_stmts(subqueries))) { @@ -4864,8 +4809,8 @@ int ObDMLStmt::check_hint_table_matched_table_item(ObCollationType cs_type, return ret; } -int ObDMLStmt::CheckConstraintItem::deep_copy(ObIRawExprCopier &expr_copier, - const CheckConstraintItem &other) +int CheckConstraintItem::deep_copy(ObIRawExprCopier &expr_copier, + const CheckConstraintItem &other) { int ret = OB_SUCCESS; if (OB_FAIL(expr_copier.copy(other.check_constraint_exprs_, check_constraint_exprs_))) { @@ -4879,7 +4824,7 @@ int ObDMLStmt::CheckConstraintItem::deep_copy(ObIRawExprCopier &expr_copier, return ret; } -int ObDMLStmt::CheckConstraintItem::assign(const CheckConstraintItem &other) +int CheckConstraintItem::assign(const CheckConstraintItem &other) { int ret = OB_SUCCESS; if (OB_FAIL(check_constraint_exprs_.assign(other.check_constraint_exprs_))) { diff --git a/src/sql/resolver/dml/ob_dml_stmt.h b/src/sql/resolver/dml/ob_dml_stmt.h index 0a2a303099..d5f645ce42 100644 --- a/src/sql/resolver/dml/ob_dml_stmt.h +++ b/src/sql/resolver/dml/ob_dml_stmt.h @@ -34,122 +34,24 @@ class ObStmtResolver; class ObDMLStmt; class ObStmtExprVisitor; class ObStmtExprGetter; +struct TransposeDef; -struct TransposeItem +struct ObUnpivotItem { - enum UnpivotNullsType - { - UNT_NOT_SET = 0, - UNT_EXCLUDE, - UNT_INCLUDE, - }; +public: + ObUnpivotItem() : is_include_null_(false) {} - struct AggrPair - { - ObRawExpr *expr_; - ObString alias_name_; - AggrPair() : expr_(NULL), alias_name_() {} - ~AggrPair() {} - TO_STRING_KV(KPC_(expr), K_(alias_name)); - }; + void reset() { new (this) ObUnpivotItem(); } - struct ForPair - { - ObString column_name_; - ForPair() : column_name_() {} - ~ForPair() {} - - TO_STRING_KV(K_(column_name)); - }; - - - struct InPair - { - common::ObSEArray exprs_; - ObString pivot_expr_alias_; - common::ObSEArray column_names_; - InPair() : pivot_expr_alias_() {} - ~InPair() {} - int assign(const InPair &other); - TO_STRING_KV(K_(exprs), K_(pivot_expr_alias), K_(column_names)); - }; - - TransposeItem() - : old_column_count_(0), is_unpivot_(false), is_incude_null_(false) - {} - void reset() - { - old_column_count_ = 0; - is_unpivot_ = false; - is_incude_null_ = false; - aggr_pairs_.reset(); - for_columns_.reset(); - in_pairs_.reset(); - unpivot_columns_.reset(); - } - inline bool is_pivot() const { return !is_unpivot_; } - inline bool is_unpivot() const { return is_unpivot_; } - inline bool is_include_null() const { return is_incude_null_; } - inline bool is_exclude_null() const { return !is_incude_null_; } - inline bool need_use_unpivot_op() const - { - return is_unpivot_ && in_pairs_.count() > 1; - } - void set_pivot() { is_unpivot_ = false; } - void set_unpivot() { is_unpivot_ = true; } - void set_include_nulls(const bool is_include_nulls) - { - is_incude_null_ = is_include_nulls; - } - int assign(const TransposeItem &other); int deep_copy(ObIRawExprCopier &expr_copier, - const TransposeItem &other); - TO_STRING_KV(K_(old_column_count), K_(is_unpivot), K_(is_incude_null), K_(aggr_pairs), - K_(for_columns), K_(in_pairs), K_(unpivot_columns), K_(alias_name)); + const ObUnpivotItem &other); - int64_t old_column_count_; - bool is_unpivot_; - bool is_incude_null_; - - common::ObSEArray aggr_pairs_; - common::ObSEArray for_columns_; - common::ObSEArray in_pairs_; - common::ObSEArray unpivot_columns_; - - ObString alias_name_; -}; - -struct ObUnpivotInfo -{ -public: - OB_UNIS_VERSION(1); -public: - ObUnpivotInfo() - : is_include_null_(false), - old_column_count_(0), - for_column_count_(0), - unpivot_column_count_(0) - {} - ObUnpivotInfo(const bool is_include_null, const int64_t old_column_count, - const int64_t for_column_count, const int64_t unpivot_column_count) - : is_include_null_(is_include_null), old_column_count_(old_column_count), - for_column_count_(for_column_count), unpivot_column_count_(unpivot_column_count) - {} - - void reset() { new (this) ObUnpivotInfo(); } - OB_INLINE bool has_unpivot() const - { return old_column_count_>= 0 && unpivot_column_count_ > 0 && for_column_count_ > 0; }; - OB_INLINE int64_t get_new_column_count() const - { return unpivot_column_count_ + for_column_count_; } - OB_INLINE int64_t get_output_column_count() const - { return old_column_count_ + get_new_column_count(); } - TO_STRING_KV(K_(is_include_null), K_(old_column_count), K_(unpivot_column_count), - K_(for_column_count)); + TO_STRING_KV(K_(is_include_null), K_(origin_exprs), K_(label_exprs), K_(value_exprs)); bool is_include_null_; - int64_t old_column_count_; - int64_t for_column_count_; - int64_t unpivot_column_count_; + common::ObSEArray origin_exprs_; + common::ObSEArray label_exprs_; + common::ObSEArray value_exprs_; }; enum MulModeTableType { @@ -273,6 +175,7 @@ struct TableItem table_type_ = MAX_TABLE_TYPE; values_table_def_ = NULL; sample_info_ = nullptr; + transpose_table_def_ = NULL; } virtual TO_STRING_KV(N_TID, table_id_, @@ -306,7 +209,7 @@ struct TableItem JOINED_TABLE, CTE_TABLE, FUNCTION_TABLE, - UNPIVOT_TABLE, + TRANSPOSE_TABLE, TEMP_TABLE, LINK_TABLE, JSON_TABLE, @@ -345,6 +248,7 @@ struct TableItem bool is_has_sample_info() const { return sample_info_ != nullptr; } bool is_joined_table() const { return JOINED_TABLE == type_; } bool is_function_table() const { return FUNCTION_TABLE == type_; } + bool is_transpose_table() const { return TRANSPOSE_TABLE == type_; } bool is_link_table() const { return OB_INVALID_ID != dblink_id_; } // why not use type_, cause type_ will be changed in dblink transform rule, but dblink id don't change bool is_link_type() const { return LINK_TABLE == type_; } // after dblink transformer, LINK_TABLE will be BASE_TABLE, BASE_TABLE will be LINK_TABLE bool is_json_table() const { return JSON_TABLE == type_; } // json_table_def_->table_type_ == MulModeTableType::OB_ORA_JSON_TABLE_TYPE @@ -402,7 +306,7 @@ struct TableItem // type == BASE_TABLE? ref_id_ is the real Id of the schema // type == ALIAS_TABLE? ref_id_ is the real Id of the schema, while table_id_ new generated // type == GENERATED_TABLE? ref_id_ is the reference of the sub-query. - // type == UNPIVOT_TABLE? ref_id_ is the reference of the sub-query, + // type == TRANSPOSE_TABLE? ref_id_ is the reference of the sub-query, // which like SELECT "normal_column", // 'in_pair_literal1' AS "for_column1", 'in_pair_literal2' AS "for_column2", // "in_pair_column1" AS "unpivot_column1", "in_pair_column2" AS "unpivot_column2" @@ -449,6 +353,8 @@ struct TableItem common::ObString external_table_partition_; // sample scan infos SampleInfo *sample_info_; + // transpose table + TransposeDef *transpose_table_def_; }; struct ColumnItem @@ -645,70 +551,70 @@ public: common::ObSEArray semi_conditions_; }; -/// In fact, ObStmt is ObDMLStmt. +struct PartExprItem +{ + PartExprItem() + : table_id_(common::OB_INVALID_ID), + index_tid_(common::OB_INVALID_ID), + part_expr_(NULL), + subpart_expr_(NULL) + { + } + uint64_t table_id_; + uint64_t index_tid_; + ObRawExpr *part_expr_; + ObRawExpr *subpart_expr_; + void reset() { + table_id_ = common::OB_INVALID_ID; + index_tid_ = common::OB_INVALID_ID; + part_expr_ = NULL; + subpart_expr_ = NULL; + } + int deep_copy(ObIRawExprCopier &expr_copier, + const PartExprItem &other); + TO_STRING_KV(K_(table_id), + K_(index_tid), + KPC_(part_expr), + KPC_(subpart_expr)); +}; + +enum CheckConstraintFlag +{ + IS_ENABLE_CHECK = 1, + IS_VALIDATE_CHECK = 1 << 1, + IS_RELY_CHECK = 1 << 2 +}; +struct CheckConstraintItem +{ + CheckConstraintItem() + : table_id_(common::OB_INVALID_ID), + ref_table_id_(common::OB_INVALID_ID), + check_constraint_exprs_(), + check_flags_() + { + } + void reset() { + table_id_ = common::OB_INVALID_ID; + ref_table_id_ = common::OB_INVALID_ID; + check_constraint_exprs_.reset(); + check_flags_.reset(); + } + int deep_copy(ObIRawExprCopier &expr_copier, + const CheckConstraintItem &other); + int assign(const CheckConstraintItem &other); + TO_STRING_KV(K_(table_id), + K_(ref_table_id), + K_(check_constraint_exprs), + K_(check_flags)); + uint64_t table_id_; + uint64_t ref_table_id_; + ObSEArray check_constraint_exprs_; + ObSEArray check_flags_; +}; + class ObDMLStmt : public ObStmt { public: - struct PartExprItem - { - PartExprItem() - : table_id_(common::OB_INVALID_ID), - index_tid_(common::OB_INVALID_ID), - part_expr_(NULL), - subpart_expr_(NULL) - { - } - uint64_t table_id_; - uint64_t index_tid_; - ObRawExpr *part_expr_; - ObRawExpr *subpart_expr_; - void reset() { - table_id_ = common::OB_INVALID_ID; - index_tid_ = common::OB_INVALID_ID; - part_expr_ = NULL; - subpart_expr_ = NULL; - } - int deep_copy(ObIRawExprCopier &expr_copier, - const PartExprItem &other); - TO_STRING_KV(K_(table_id), - K_(index_tid), - KPC_(part_expr), - KPC_(subpart_expr)); - }; - - enum CheckConstraintFlag - { - IS_ENABLE_CHECK = 1, - IS_VALIDATE_CHECK = 1 << 1, - IS_RELY_CHECK = 1 << 2 - }; - struct CheckConstraintItem - { - CheckConstraintItem() - : table_id_(common::OB_INVALID_ID), - ref_table_id_(common::OB_INVALID_ID), - check_constraint_exprs_(), - check_flags_() - { - } - void reset() { - table_id_ = common::OB_INVALID_ID; - ref_table_id_ = common::OB_INVALID_ID; - check_constraint_exprs_.reset(); - check_flags_.reset(); - } - int deep_copy(ObIRawExprCopier &expr_copier, - const CheckConstraintItem &other); - int assign(const CheckConstraintItem &other); - TO_STRING_KV(K_(table_id), - K_(ref_table_id), - K_(check_constraint_exprs), - K_(check_flags)); - uint64_t table_id_; - uint64_t ref_table_id_; - ObSEArray check_constraint_exprs_; - ObSEArray check_flags_; - }; typedef common::hash::ObHashMap, @@ -1180,22 +1086,9 @@ public: const uint64_t seq_id) const; int get_sequence_exprs(common::ObIArray &exprs) const; int get_udf_exprs(common::ObIArray &exprs) const; - const TransposeItem *get_transpose_item() const { return transpose_item_; } - void set_transpose_item(const TransposeItem *transpose_item) { transpose_item_ = transpose_item; } - const ObUnpivotInfo get_unpivot_info() const - { - return (transpose_item_ != NULL - ? ObUnpivotInfo(transpose_item_->is_include_null(), - transpose_item_->old_column_count_, - transpose_item_->for_columns_.count(), - transpose_item_->unpivot_columns_.count()) - : ObUnpivotInfo()); - } - bool is_unpivot_select() const - { - const ObUnpivotInfo &unpivot_info = get_unpivot_info(); - return unpivot_info.has_unpivot(); - } + const ObUnpivotItem *get_unpivot_item() const { return unpivot_item_; } + void set_unpivot_item(ObUnpivotItem *unpivot_item) { unpivot_item_ = unpivot_item; } + bool is_unpivot_select() const { return unpivot_item_ != NULL; } int remove_subquery_expr(const ObRawExpr *expr); // rebuild query ref exprs int adjust_subquery_list(); @@ -1358,7 +1251,7 @@ protected: common::ObSEArray pseudo_column_like_exprs_; ObDMLStmtTableHash tables_hash_; common::ObSEArray subquery_exprs_; - const TransposeItem *transpose_item_; + ObUnpivotItem *unpivot_item_; common::ObSEArray user_var_exprs_; common::ObSEArray check_constraint_items_; diff --git a/src/sql/resolver/dml/ob_group_by_checker.cpp b/src/sql/resolver/dml/ob_group_by_checker.cpp index 21eebe54c7..b42447e7cd 100644 --- a/src/sql/resolver/dml/ob_group_by_checker.cpp +++ b/src/sql/resolver/dml/ob_group_by_checker.cpp @@ -914,6 +914,16 @@ int ObGroupByChecker::visit(ObMatchFunRawExpr &expr) return ret; } +int ObGroupByChecker::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_SUCCESS; + if (find_in_group_by(expr) || find_in_rollup(expr) || + find_in_cube(expr) || find_in_grouping_sets(expr)) { + set_skip_expr(&expr); + } + return ret; +} + // following case is allowed // select max(max(data)) from test group by id order by id, max(max(data)) ; diff --git a/src/sql/resolver/dml/ob_group_by_checker.h b/src/sql/resolver/dml/ob_group_by_checker.h index 368d9746c3..20c7f40c3d 100644 --- a/src/sql/resolver/dml/ob_group_by_checker.h +++ b/src/sql/resolver/dml/ob_group_by_checker.h @@ -66,6 +66,7 @@ public: virtual int visit(ObPseudoColumnRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); // set expr skip virtual bool skip_child(ObRawExpr &expr) diff --git a/src/sql/resolver/dml/ob_select_resolver.cpp b/src/sql/resolver/dml/ob_select_resolver.cpp index e72eeadd70..a54f1797cd 100644 --- a/src/sql/resolver/dml/ob_select_resolver.cpp +++ b/src/sql/resolver/dml/ob_select_resolver.cpp @@ -45,7 +45,6 @@ ObSelectResolver::ObSelectResolver(ObResolverParams ¶ms) is_sub_stmt_(false), in_exists_subquery_(false), standard_group_checker_(), - transpose_item_(NULL), is_left_child_(false), having_has_self_column_(false), has_grouping_(false), @@ -2665,9 +2664,7 @@ int ObSelectResolver::expand_target_list( LOG_WARN("unexpected table type", K_(table_item.type), K(ret)); } - const bool is_child_unpivot_select = (NULL != table_item.ref_query_ - && table_item.ref_query_->is_unpivot_select()); - LOG_DEBUG("do expand_target_list", K(is_child_unpivot_select), KPC(table_item.ref_query_)); + LOG_DEBUG("do expand_target_list", KPC(table_item.ref_query_)); for (int64_t i = 0; OB_SUCC(ret) && i < column_items.count(); ++i) { const ColumnItem &col_item = column_items.at(i); SelectItem tmp_select_item; @@ -2678,26 +2675,22 @@ int ObSelectResolver::expand_target_list( K(i), K(table_item.ref_query_->get_select_item_size())); } else { const SelectItem &select_item = table_item.ref_query_->get_select_item(i); - if (is_child_unpivot_select && select_item.is_unpivot_mocked_column_) { - LOG_DEBUG("continue", K(select_item)); - continue; - } else { - tmp_select_item.questions_pos_ = select_item.questions_pos_; - tmp_select_item.params_idx_ = select_item.params_idx_; - tmp_select_item.neg_param_idx_ = select_item.neg_param_idx_; - tmp_select_item.esc_str_flag_ = select_item.esc_str_flag_; - tmp_select_item.paramed_alias_name_ = select_item.paramed_alias_name_; - tmp_select_item.need_check_dup_name_ = select_item.need_check_dup_name_; - tmp_select_item.is_unpivot_mocked_column_ = select_item.is_unpivot_mocked_column_; - } + tmp_select_item.questions_pos_ = select_item.questions_pos_; + tmp_select_item.params_idx_ = select_item.params_idx_; + tmp_select_item.neg_param_idx_ = select_item.neg_param_idx_; + tmp_select_item.esc_str_flag_ = select_item.esc_str_flag_; + tmp_select_item.paramed_alias_name_ = select_item.paramed_alias_name_; + tmp_select_item.need_check_dup_name_ = select_item.need_check_dup_name_; } } - tmp_select_item.alias_name_ = col_item.column_name_; - tmp_select_item.expr_name_ = col_item.column_name_; - tmp_select_item.is_real_alias_ = false; - tmp_select_item.expr_ = col_item.expr_; - if (OB_FAIL(target_list.push_back(tmp_select_item))) { - LOG_WARN("push back target list failed", K(ret)); + if (OB_SUCC(ret)) { + tmp_select_item.alias_name_ = col_item.column_name_; + tmp_select_item.expr_name_ = col_item.column_name_; + tmp_select_item.is_real_alias_ = false; + tmp_select_item.expr_ = col_item.expr_; + if (OB_FAIL(target_list.push_back(tmp_select_item))) { + LOG_WARN("push back target list failed", K(ret)); + } } } return ret; @@ -2804,6 +2797,7 @@ int ObSelectResolver::resolve_star_for_table_groups(ObStarExpansionInfo &star_ex int ret = OB_SUCCESS; int64_t num = 0; int64_t jointable_idx = -1; + ObSEArray visited_jointable_idx; bool oracle_star_expand = lib::is_oracle_mode() && is_top_stmt(); if (OB_ISNULL(select_stmt)) { ret = OB_ERR_UNEXPECTED; @@ -2843,11 +2837,13 @@ int ObSelectResolver::resolve_star_for_table_groups(ObStarExpansionInfo &star_ex LOG_WARN("find_joined_table_group_for_table failed", K(ret), K(table_item)); } else if (jointable_idx != -1) { // located in joined table with jointable_idx of joined_tables - if (OB_FAIL(find_select_columns_for_join_group(jointable_idx, &target_list))) { + if (is_contain(visited_jointable_idx, jointable_idx)) { + // skip table in visited joined group + } else if (OB_FAIL(find_select_columns_for_join_group(jointable_idx, &target_list))) { LOG_WARN("find_select_columns_for_join_group failed", K(ret)); + } else if (OB_FAIL(visited_jointable_idx.push_back(jointable_idx))) { + LOG_WARN("failed to push back", K(ret)); } else { - // skip next tables in joined group - i += select_stmt->get_joined_tables().at(jointable_idx)->single_table_ids_.count() - 1; // push back select items to select stmt for (int j = 0; OB_SUCC(ret) && j < target_list.count(); j++) { SelectItem &item = target_list.at(j); @@ -2954,11 +2950,6 @@ int ObSelectResolver::resolve_all_generated_table_columns( static_cast(select_item.expr_)->is_joined_dup_column():false; bool need_check_col_dup = true; bool is_skip = is_oracle_mode() && !table_ref->is_view_stmt() && is_joined_dup_column; - /* 这里进行一次重复列名检测是原因是oracle支持generated table含有重复列名的不引用重复列名的查询,比如: - * select 1 from (select c1,c1 from t1);因此在oracle模式resolve generated table时会跳过检查重复列 - * 但是对于select * from(select c1,c1 from t1);这样的查询肯定引用了,因此必须在展开*对应的查询时进行一次 - * 检查,如果存在重复列是不允许的; - */ if (OB_FAIL(resolve_generated_table_column_item(table_item, select_item.alias_name_, col_item, @@ -3970,146 +3961,11 @@ int ObSelectResolver::resolve_from_clause(const ParseNode *node) select_stmt->set_has_reverse_link(table_item->is_reverse_link_); } } - OZ( gen_unpivot_target_column(node->num_child_, *select_stmt, *table_item) ); OZ( check_recursive_cte_usage(*select_stmt) ); } return ret; } -int ObSelectResolver::gen_unpivot_target_column(const int64_t table_count, - ObSelectStmt &select_stmt, TableItem &table_item) -{ - int ret = OB_SUCCESS; - if (NULL != transpose_item_ && 1 == table_count) { - select_stmt.set_from_pivot(transpose_item_->is_pivot()); - //mark this stmt is transpose item - if (transpose_item_->is_unpivot() && transpose_item_->need_use_unpivot_op()) { - //use unpivot operation - select_stmt.set_transpose_item(const_cast(transpose_item_)); - - const int64_t old_column_count = transpose_item_->old_column_count_; - const int64_t new_column_count = transpose_item_->unpivot_columns_.count() - + transpose_item_->for_columns_.count(); - - ObSelectStmt *child_select_stmt = table_item.ref_query_; - int64_t select_item_count = 0; - ObCollationType coll_type = CS_TYPE_INVALID; - LOG_DEBUG("begin gen_unpivot_target_column", K(table_item), KPC(child_select_stmt)); - if (OB_ISNULL(params_.expr_factory_) - || OB_ISNULL(session_info_) - || OB_ISNULL(child_select_stmt) - || FALSE_IT(select_item_count = child_select_stmt->get_select_item_size()) - || OB_UNLIKELY(new_column_count < 0) - || OB_UNLIKELY(old_column_count < 0) - || OB_UNLIKELY(old_column_count >= select_item_count) - || OB_UNLIKELY((select_item_count - old_column_count) % new_column_count != 0) - || OB_UNLIKELY((select_item_count - old_column_count) / new_column_count <= 1) - ) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("params is invalid", K(ret), K(table_item), - K(params_.expr_factory_), K(old_column_count), K(new_column_count), - K(select_item_count), KPC(child_select_stmt)); - } else if (OB_FAIL(session_info_->get_collation_connection(coll_type))) { - LOG_WARN("fail to get_collation_connection", K(ret)); - } else { - ObSEArray types; - ObExprResType res_type; - ObExprVersion dummy_op(*allocator_); - ObExprTypeCtx type_ctx; - ObSQLUtils::init_type_ctx(session_info_, type_ctx); - for (int64_t colum_idx = 0; OB_SUCC(ret) && colum_idx < new_column_count; colum_idx++) { - res_type.reset(); - types.reset(); - - int64_t item_idx = old_column_count + colum_idx; - SelectItem &first_select_item = child_select_stmt->get_select_item(item_idx); - item_idx += new_column_count; - if (OB_ISNULL(first_select_item.expr_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("expr is null", K(ret), K(first_select_item.expr_)); - } else if (OB_FAIL(types.push_back(first_select_item.expr_->get_result_type()))) { - LOG_WARN("fail to push left_type", K(ret)); - } - while (OB_SUCC(ret) && item_idx < select_item_count) { - SelectItem &tmp_select_item = child_select_stmt->get_select_item(item_idx); - if (OB_ISNULL(tmp_select_item.expr_) ) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("expr is null", K(ret), K(tmp_select_item.expr_)); - } else if (first_select_item.expr_->get_result_type() - != tmp_select_item.expr_->get_result_type()) { - const ObExprResType &first_type = first_select_item.expr_->get_result_type(); - const ObExprResType &tmp_type = tmp_select_item.expr_->get_result_type(); - if (!((first_type.is_null() && !tmp_type.is_lob()) - || (tmp_type.is_null() && !first_type.is_lob()) - || (first_type.is_character_type() && tmp_type.is_character_type()) - || (ob_is_oracle_numeric_type(first_type.get_type()) - && ob_is_oracle_numeric_type(tmp_type.get_type())) - || (ob_is_oracle_temporal_type(first_type.get_type()) - && (ob_is_oracle_temporal_type(tmp_type.get_type()))))) { - ret = OB_ERR_EXP_NEED_SAME_DATATYPE; - LOG_WARN("expression must have same datatype as corresponding expression", K(ret), - K(first_type), K(tmp_type)); - } else if (first_type.is_character_type() - && tmp_type.is_character_type() - && (first_type.is_varchar_or_char() != tmp_type.is_varchar_or_char())) { - ret = OB_ERR_CHARACTER_SET_MISMATCH; - LOG_WARN("character set mismatch", K(ret), K(first_type), K(tmp_type)); - } else if (OB_FAIL(types.push_back(tmp_type))) { - LOG_WARN("fail to push type", K(ret), K(tmp_type)); - } - } - item_idx += new_column_count; - } - - if (OB_SUCC(ret)) { - if (types.count() == 1) { - res_type = first_select_item.expr_->get_result_type(); - } else if (OB_FAIL(dummy_op.aggregate_result_type_for_merge(res_type, - &types.at(0), - types.count(), - true, - type_ctx))) { - LOG_WARN("fail to aggregate_result_type_for_merge", K(ret), K(types)); - } - } - - if (OB_SUCC(ret)) { - if (OB_UNLIKELY(ObNullType == res_type.get_type() || ObMaxType == res_type.get_type())) { - ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN("column type incompatible", K(ret), K(res_type)); - } else { - item_idx = old_column_count + colum_idx; - while (OB_SUCC(ret) && item_idx < select_item_count) { - SelectItem &select_item = child_select_stmt->get_select_item(item_idx); - if (select_item.expr_->get_result_type() != res_type) { - ObSysFunRawExpr *new_expr = NULL; - if (OB_FAIL(ObRawExprUtils::create_cast_expr(*params_.expr_factory_, - select_item.expr_, - res_type, - new_expr, - session_info_))) { - LOG_WARN("create cast expr for stmt failed", K(ret)); - } else if (OB_FAIL(new_expr->add_flag(IS_INNER_ADDED_EXPR))) { - LOG_WARN("failed to add flag", K(ret)); - } else { - select_item.expr_ = new_expr; - LOG_DEBUG("add cast for column", K(select_item), K(res_type)); - } - } - item_idx += new_column_count; - } - } - } - }//end of for - } - LOG_DEBUG("finish gen_unpivot_target_column", K(table_item), KPC(child_select_stmt)); - } - //reset - transpose_item_ = NULL; - } - return ret; -} - int ObSelectResolver::resolve_group_clause(const ParseNode *node) { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/dml/ob_select_resolver.h b/src/sql/resolver/dml/ob_select_resolver.h index d9c4f64088..36dee6e168 100644 --- a/src/sql/resolver/dml/ob_select_resolver.h +++ b/src/sql/resolver/dml/ob_select_resolver.h @@ -71,7 +71,6 @@ public: void set_in_exists_subquery(bool in_exists_subquery) { in_exists_subquery_ = in_exists_subquery; } bool is_in_exists_subquery() const { return in_exists_subquery_; } virtual int resolve_column_ref_expr(const ObQualifiedName &q_name, ObRawExpr *&real_ref_expr); - void set_transpose_item(const TransposeItem *transpose_item) { transpose_item_ = transpose_item; } void set_is_left_child(const bool is_left_child) { is_left_child_ = is_left_child; } void set_having_has_self_column() { having_has_self_column_ = true; } bool has_having_self_column() const { return having_has_self_column_; } @@ -251,9 +250,11 @@ protected: int resolve_table_column_ref(const ObQualifiedName &q_name, ObRawExpr *&real_ref_expr); int resolve_alias_column_ref(const ObQualifiedName &q_name, ObRawExpr *&real_ref_expr); int resolve_column_ref_in_group_by(const ObQualifiedName &q_name, ObRawExpr *&real_ref_expr); +public: int resolve_all_function_table_columns(const TableItem &table_item, ObIArray *column_items); int resolve_all_json_table_columns(const TableItem &table_item, ObIArray *column_items); int resolve_all_generated_table_columns(const TableItem &table_item, common::ObIArray *column_items); +protected: virtual int set_select_item(SelectItem &select_item, bool is_auto_gen); int resolve_query_options(const ParseNode *node); virtual int resolve_subquery_info(const common::ObIArray &subquery_info); @@ -397,7 +398,6 @@ protected: // query is subquery in exists bool in_exists_subquery_; ObStandardGroupChecker standard_group_checker_; - const TransposeItem *transpose_item_; bool is_left_child_; uint64_t auto_name_id_; // denote having exists ref columns that belongs to current stmt diff --git a/src/sql/resolver/dml/ob_select_stmt.cpp b/src/sql/resolver/dml/ob_select_stmt.cpp index 7fec5e0a80..b6bc96b06a 100644 --- a/src/sql/resolver/dml/ob_select_stmt.cpp +++ b/src/sql/resolver/dml/ob_select_stmt.cpp @@ -36,7 +36,6 @@ int SelectItem::deep_copy(ObIRawExprCopier &expr_copier, esc_str_flag_ = other.esc_str_flag_; need_check_dup_name_ = other.need_check_dup_name_; implicit_filled_ = other.implicit_filled_; - is_unpivot_mocked_column_ = other.is_unpivot_mocked_column_; is_implicit_added_ = other.is_implicit_added_; is_hidden_rowid_ = other.is_hidden_rowid_; } @@ -735,7 +734,6 @@ int ObSelectStmt::do_to_string(char *buf, const int64_t buf_len, int64_t &pos) c } else { J_KV( N_STMT_TYPE, stmt_type_, - K_(transpose_item), N_TABLE, table_items_, N_JOINED_TABLE, joined_tables_, N_SEMI_INFO, semi_infos_, @@ -1006,15 +1004,12 @@ bool ObSelectStmt::is_spjg() const return bret; } -int ObSelectStmt::get_select_exprs(ObIArray &select_exprs, - const bool is_for_outout/* = false*/) +int ObSelectStmt::get_select_exprs(ObIArray &select_exprs) { int ret = OB_SUCCESS; ObRawExpr *expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < select_items_.count(); ++i) { - if (is_for_outout && select_items_.at(i).is_unpivot_mocked_column_) { - //continue - } else if (OB_ISNULL(expr = select_items_.at(i).expr_)) { + if (OB_ISNULL(expr = select_items_.at(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null select expr", K(ret)); } else if (OB_FAIL(select_exprs.push_back(expr))) { @@ -1024,16 +1019,13 @@ int ObSelectStmt::get_select_exprs(ObIArray &select_exprs, return ret; } -int ObSelectStmt::get_select_exprs(ObIArray &select_exprs, - const bool is_for_outout/* = false*/) const +int ObSelectStmt::get_select_exprs(ObIArray &select_exprs) const { int ret = OB_SUCCESS; ObRawExpr *expr = NULL; LOG_DEBUG("before get_select_exprs", K(select_items_), K(table_items_), K(lbt())); for (int64_t i = 0; OB_SUCC(ret) && i < select_items_.count(); ++i) { - if (is_for_outout && select_items_.at(i).is_unpivot_mocked_column_) { - //continue - } else if (OB_ISNULL(expr = select_items_.at(i).expr_)) { + if (OB_ISNULL(expr = select_items_.at(i).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null select expr", K(ret)); } else if (OB_FAIL(select_exprs.push_back(expr))) { diff --git a/src/sql/resolver/dml/ob_select_stmt.h b/src/sql/resolver/dml/ob_select_stmt.h index c91f4915e7..38df23bcb4 100644 --- a/src/sql/resolver/dml/ob_select_stmt.h +++ b/src/sql/resolver/dml/ob_select_stmt.h @@ -46,7 +46,6 @@ struct SelectItem esc_str_flag_(false), need_check_dup_name_(false), implicit_filled_(false), - is_unpivot_mocked_column_(false), is_implicit_added_(false), is_hidden_rowid_(false) { @@ -64,7 +63,6 @@ struct SelectItem esc_str_flag_ = false; need_check_dup_name_ = false; implicit_filled_ = false; - is_unpivot_mocked_column_ = false; is_implicit_added_ = false; is_hidden_rowid_ = false; } @@ -89,7 +87,6 @@ struct SelectItem K_(esc_str_flag), K_(need_check_dup_name), K_(implicit_filled), - K_(is_unpivot_mocked_column), K_(is_hidden_rowid)); ObRawExpr *expr_; @@ -107,7 +104,6 @@ struct SelectItem bool need_check_dup_name_; // select item is implicit filled in updatable view, to pass base table's column to top view. bool implicit_filled_; - bool is_unpivot_mocked_column_; //used for unpivot bool is_implicit_added_; //used for temporary table and label security at insert resolver bool is_hidden_rowid_; @@ -516,8 +512,8 @@ public: SelectItem &get_select_item(int64_t index) { return select_items_[index]; } common::ObIArray &get_select_items() { return select_items_; } const common::ObIArray &get_select_items() const { return select_items_; } - int get_select_exprs(ObIArray &select_exprs, const bool is_for_outout = false); - int get_select_exprs(ObIArray &select_exprs, const bool is_for_outout = false) const; + int get_select_exprs(ObIArray &select_exprs); + int get_select_exprs(ObIArray &select_exprs) const; int get_select_exprs_without_lob(ObIArray &select_exprs) const; const common::ObIArray &get_aggr_items() const { return agg_items_; } common::ObIArray &get_aggr_items() { return agg_items_; } diff --git a/src/sql/resolver/dml/ob_standard_group_checker.h b/src/sql/resolver/dml/ob_standard_group_checker.h index 72f531586f..76a9c91491 100644 --- a/src/sql/resolver/dml/ob_standard_group_checker.h +++ b/src/sql/resolver/dml/ob_standard_group_checker.h @@ -83,6 +83,7 @@ public: virtual int visit(ObPseudoColumnRawExpr &expr) { UNUSED(expr); return OB_SUCCESS; } virtual int visit(ObPlQueryRefRawExpr &expr) { UNUSED(expr); return OB_SUCCESS; } virtual int visit(ObMatchFunRawExpr &expr) { UNUSED(expr); return OB_SUCCESS; } + virtual int visit(ObUnpivotRawExpr &expr) { UNUSED(expr); return OB_SUCCESS; } virtual bool skip_child(ObRawExpr &expr); private: ObStandardGroupChecker *checker_; diff --git a/src/sql/resolver/dml/ob_transpose_resolver.cpp b/src/sql/resolver/dml/ob_transpose_resolver.cpp new file mode 100644 index 0000000000..f34de97f48 --- /dev/null +++ b/src/sql/resolver/dml/ob_transpose_resolver.cpp @@ -0,0 +1,1594 @@ +/** + * 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_RESV + +#include "sql/resolver/dml/ob_transpose_resolver.h" +#include "sql/engine/expr/ob_expr_version.h" +#include "sql/resolver/dml/ob_dml_resolver.h" +#include "sql/resolver/dml/ob_select_resolver.h" +#include "sql/rewrite/ob_transform_pre_process.h" +#include "sql/rewrite/ob_transform_utils.h" +#include "sql/optimizer/ob_optimizer_util.h" + +namespace oceanbase { + +using namespace common; + +namespace sql { + +int TransposeDef::assign(const TransposeDef &other) +{ + int ret = OB_SUCCESS; + if (this == &other) { + //do nothing + } else { + alias_name_ = other.alias_name_; + orig_table_item_ = other.orig_table_item_; + } + return ret; +} + +int TransposeDef::deep_copy(ObIRawExprCopier &expr_copier, + const TransposeDef &other) +{ + int ret = OB_NOT_SUPPORTED; + LOG_WARN("transpose item should not deep copy", K(ret)); + return ret; +} + +int PivotDef::AggrPair::assign(const PivotDef::AggrPair &other) +{ + int ret = OB_SUCCESS; + if (this == &other) { + //do nothing + } else { + expr_ = other.expr_; + alias_name_ = other.alias_name_; + } + return ret; +} + +int PivotDef::InPair::assign(const PivotDef::InPair &other) +{ + int ret = OB_SUCCESS; + if (this == &other) { + //do nothing + } else if (OB_FAIL(const_exprs_.assign(other.const_exprs_))) { + LOG_WARN("assign searray failed", K(other), K(ret)); + } else { + name_ = other.name_; + } + return ret; +} + +int PivotDef::assign(const PivotDef &other) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(TransposeDef::assign(other))) { + LOG_WARN("failed to assign transpose def", K(ret)); + } else if (OB_FAIL(group_columns_.assign(other.group_columns_)) || + OB_FAIL(group_column_names_.assign(other.group_column_names_)) || + OB_FAIL(for_columns_.assign(other.for_columns_)) || + OB_FAIL(for_column_names_.assign(other.for_column_names_)) || + OB_FAIL(aggr_pairs_.assign(other.aggr_pairs_)) || + OB_FAIL(in_pairs_.assign(other.in_pairs_))) { + LOG_WARN("failed to assign", K(ret)); + } + return ret; +} + +int UnpivotDef::InPair::assign(const UnpivotDef::InPair &other) +{ + int ret = OB_SUCCESS; + if (this == &other) { + //do nothing + } else if (OB_FAIL(const_exprs_.assign(other.const_exprs_))) { + LOG_WARN("assign searray failed", K(other), K(ret)); + } else if (OB_FAIL(column_names_.assign(other.column_names_))) { + LOG_WARN("assign searray failed", K(other), K(ret)); + } else if (OB_FAIL(column_exprs_.assign(other.column_exprs_))) { + LOG_WARN("assign searray failed", K(other), K(ret)); + } + return ret; +} + +int UnpivotDef::assign(const UnpivotDef &other) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(TransposeDef::assign(other))) { + LOG_WARN("failed to assign transpose def", K(ret)); + } else if (OB_FAIL(orig_columns_.assign(other.orig_columns_)) || + OB_FAIL(orig_column_names_.assign(other.orig_column_names_)) || + OB_FAIL(label_columns_.assign(other.label_columns_)) || + OB_FAIL(value_columns_.assign(other.value_columns_)) || + OB_FAIL(in_pairs_.assign(other.in_pairs_))) { + LOG_WARN("failed to assign", K(ret)); + } else { + is_include_null_ = other.is_include_null_; + } + return ret; +} + +// transpose_table_node +// |--table_node +// |--transpose_node +// |--alias +// resolve table_node +// resolve transpose_table +int ObTransposeResolver::resolve(const ParseNode &parse_tree) { + int ret = OB_SUCCESS; + void *table_item_ptr = NULL; + bool tmp_has_same_table_name = false; + ParseNode *origin_table = NULL; + ParseNode *transpose_node = NULL; + ObResolverParams *params = NULL; + ObDMLStmt *stmt = NULL; + TableItem *orig_table_item = NULL; + if (T_TRANSPOSE_TABLE != parse_tree.type_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid transpose parse tree type", K(ret)); + } else if (OB_ISNULL(cur_resolver_) || OB_ISNULL(stmt = cur_resolver_->get_stmt()) || + OB_ISNULL(origin_table = parse_tree.children_[0]) || + OB_ISNULL(transpose_node = parse_tree.children_[1]) || + FALSE_IT(params = &cur_resolver_->params_) || + OB_ISNULL(params->allocator_) || + OB_ISNULL(params->expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (FALSE_IT(tmp_has_same_table_name = params->have_same_table_name_)) { + } else if (OB_FAIL(cur_resolver_->resolve_table(*origin_table, orig_table_item))) { + LOG_WARN("failed to resolve table", K(ret)); + } else if (FALSE_IT(params->have_same_table_name_ = tmp_has_same_table_name)) { + } else { + TransposeDef *trans_def = NULL; + ObColumnNamespaceChecker &column_namespace_checker = cur_resolver_->get_column_namespace_checker(); + ObSEArray columns_in_aggrs; + if (OB_ISNULL(orig_table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table_item or stmt is unexpected", KP(orig_table_item), K(ret)); + } else if (FALSE_IT(column_namespace_checker.set_transpose_origin_table(*orig_table_item))) { + } else if (OB_FAIL(resolve_transpose_clause(*transpose_node, *orig_table_item, trans_def, columns_in_aggrs))) { + LOG_WARN("resolve transpose clause failed", K(ret)); + } else if (OB_ISNULL(trans_def)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (trans_def->need_use_unpivot_op() && + OB_FAIL(try_add_cast_to_unpivot(static_cast(*trans_def)))) { + LOG_WARN("fail to add cast to unpivot", KPC(orig_table_item), K(ret)); + } else if (OB_FAIL(get_old_or_group_column(columns_in_aggrs, *orig_table_item, *trans_def))) { + LOG_WARN("fail to get old or group column", KPC(orig_table_item), K(ret)); + } else if (OB_FAIL(transform_to_view(*orig_table_item, *trans_def, table_item_))) { + LOG_WARN("failed to transform to view", K(ret)); + } else { + cur_resolver_->get_column_namespace_checker().clear_transpose(); + trans_def->orig_table_item_ = orig_table_item; + // for print stmt + table_item_->transpose_table_def_ = trans_def; + } + } + return ret; +} + +int ObTransposeResolver::resolve_transpose_clause( + const ParseNode &transpose_node, + TableItem &orig_table_item, + TransposeDef *&trans_def, + ObIArray &columns_in_aggrs) +{ + int ret = OB_SUCCESS; + void *ptr = NULL; + if (OB_ISNULL(cur_resolver_) + || OB_ISNULL(cur_resolver_->get_stmt()) + || OB_UNLIKELY(transpose_node.type_ != T_PIVOT && transpose_node.type_ != T_UNPIVOT) + || OB_UNLIKELY(transpose_node.num_child_ != 4) + || OB_ISNULL(transpose_node.children_) + || OB_ISNULL(transpose_node.children_[0]) + || OB_ISNULL(transpose_node.children_[1]) + || OB_ISNULL(transpose_node.children_[2]) + || OB_ISNULL(transpose_node.children_[3])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("transpose_node is unexpected", K(transpose_node.type_), K(transpose_node.num_child_), + KP(transpose_node.children_), K(ret)); + } else if (T_PIVOT == transpose_node.type_) { + if (OB_ISNULL(ptr = cur_resolver_->params_.allocator_->alloc(sizeof(PivotDef)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("create unpivot info failed"); + } else { + PivotDef * pivot_def = new (ptr) PivotDef(); + // resolve pivot clause + if (OB_FAIL(resolve_pivot_clause(transpose_node, orig_table_item, *pivot_def, columns_in_aggrs))) { + LOG_WARN("failed to resolve pivot clause", K(ret)); + } else { + trans_def = pivot_def; + } + } + } else { + if (OB_ISNULL(ptr = cur_resolver_->params_.allocator_->alloc(sizeof(UnpivotDef)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("create unpivot info failed"); + } else { + UnpivotDef * unpivot_def = new (ptr) UnpivotDef(); + // resolve unpivot clause + if (OB_FAIL(resolve_unpivot_clause(transpose_node, orig_table_item, *unpivot_def))) { + LOG_WARN("failed to resolve pivot clause", K(ret)); + } else { + trans_def = unpivot_def; + } + } + } + //alias + if (OB_SUCC(ret)) { + const ParseNode &alias = *transpose_node.children_[3]; + if (alias.str_len_ > 0 && alias.str_value_ != NULL) { + trans_def->alias_name_.assign_ptr(alias.str_value_, alias.str_len_); + } else if (OB_FAIL(cur_resolver_->get_stmt()->generate_anonymous_view_name( + *cur_resolver_->params_.allocator_, trans_def->alias_name_))) { + LOG_WARN("failed to generate anonymous view name", K(ret)); + } + } + LOG_DEBUG("finish resolve_transpose_clause", K(trans_def), K(columns_in_aggrs), K(ret)); + return ret; +} + +int ObTransposeResolver::resolve_pivot_clause( + const ParseNode &transpose_node, + TableItem &orig_table_item, + PivotDef &pivot_def, + common::ObIArray &columns_in_aggrs) +{ + int ret = OB_SUCCESS; + //pivot aggr + const ParseNode &aggr_node = *transpose_node.children_[0]; + if (OB_UNLIKELY(aggr_node.type_ != T_PIVOT_AGGR_LIST) + || OB_UNLIKELY(aggr_node.num_child_ <= 0) + || OB_ISNULL(aggr_node.children_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("aggr_node is unexpected", K(aggr_node.type_), K(aggr_node.num_child_), + KP(aggr_node.children_), K(ret)); + } else { + ObArray qualified_name_in_aggr; + for (int64_t i = 0; OB_SUCC(ret) && i < aggr_node.num_child_; ++i) { + const ParseNode *tmp_node = aggr_node.children_[i]; + const ParseNode *alias_node = NULL; + PivotDef::AggrPair aggr_pair; + qualified_name_in_aggr.reuse(); + if (OB_ISNULL(tmp_node) + || OB_UNLIKELY(tmp_node->type_ != T_PIVOT_AGGR) + || OB_UNLIKELY(tmp_node->num_child_ != 2) + || OB_ISNULL(tmp_node->children_) + || OB_ISNULL(tmp_node->children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("tmp_node is unexpected", KP(tmp_node), K(ret)); + } else if (OB_FAIL(cur_resolver_->resolve_sql_expr(*tmp_node->children_[0], + aggr_pair.expr_, + &qualified_name_in_aggr))) { + LOG_WARN("fail to resolve_sql_expr", K(ret)); + } else if (OB_FAIL(check_pivot_aggr_expr(aggr_pair.expr_))) { + LOG_WARN("fail to check_aggr_expr", K(ret)); + } else if (NULL != (alias_node = tmp_node->children_[1]) + && FALSE_IT(aggr_pair.alias_name_.assign_ptr(alias_node->str_value_, + alias_node->str_len_))) { + } else if (OB_FAIL(pivot_def.aggr_pairs_.push_back(aggr_pair))) { + LOG_WARN("fail to push_back aggr_pair", K(aggr_pair), K(ret)); + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < qualified_name_in_aggr.count(); ++j) { + ObString &column_name = qualified_name_in_aggr.at(j).col_name_; + if (!has_exist_in_array(columns_in_aggrs, column_name)) { + if (OB_FAIL(columns_in_aggrs.push_back(column_name))) { + LOG_WARN("fail to push_back column_name", K(column_name), K(ret)); + } + } + } + } + } + } + + //pivot for + if (OB_SUCC(ret)) { + if (OB_FAIL(resolve_columns(*transpose_node.children_[1], + orig_table_item, + pivot_def.for_column_names_, + pivot_def.for_columns_))) { + LOG_WARN("fail to resolve transpose columns", K(ret)); + } + } + + //pivot in + if (OB_SUCC(ret)) { + const ParseNode &in_node = *transpose_node.children_[2]; + if (OB_UNLIKELY(in_node.type_ != T_PIVOT_IN_LIST) + || OB_UNLIKELY(in_node.num_child_ <= 0) + || OB_ISNULL(in_node.children_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("in_node is unexpected", K(in_node.type_), K(in_node.num_child_), + KP(in_node.children_), K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < in_node.num_child_; ++i) { + const ParseNode *column_node = in_node.children_[i]; + const ParseNode *alias_node = NULL; + PivotDef::InPair in_pair; + if (OB_ISNULL(column_node) + || OB_UNLIKELY(column_node->type_ != T_PIVOT_IN) + || OB_UNLIKELY(column_node->num_child_ != 2) + || OB_ISNULL(column_node->children_) + || OB_ISNULL(column_node->children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column_node is unexpected", KP(column_node), K(ret)); + } else if (OB_FAIL(resolve_const_exprs(*column_node->children_[0], + in_pair.const_exprs_))) { + LOG_WARN("fail to resolve_const_exprs", K(ret)); + } else if (OB_UNLIKELY(in_pair.const_exprs_.count() != pivot_def.for_column_names_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("in expr number is not equal for columns", K(in_pair.const_exprs_), + K(pivot_def.for_column_names_), K(ret)); + } else if (NULL != (alias_node = column_node->children_[1])) { + if (OB_UNLIKELY(alias_node->str_len_ > OB_MAX_COLUMN_NAME_LENGTH)) { + ret = OB_ERR_TOO_LONG_IDENT; + LOG_WARN("alias name for pivot is too long", K(ret), + K(ObString(alias_node->str_len_, alias_node->str_value_))); + } else { + in_pair.name_.assign_ptr(alias_node->str_value_, alias_node->str_len_); + } + } else /* no alias, use const expr name as in_pair's name */ { + if (OB_FAIL(get_combine_name(in_pair.const_exprs_, in_pair.name_))) { + LOG_WARN("failed to get combine name", K(ret)); + } + } + if (OB_SUCC(ret) && OB_FAIL(pivot_def.in_pairs_.push_back(in_pair))) { + LOG_WARN("fail to push_back in_pair", K(in_pair), K(ret)); + } + }//end of for in node + } + } + return ret; +} + +int ObTransposeResolver::resolve_unpivot_clause(const ParseNode &transpose_node, + TableItem &orig_table_item, + UnpivotDef &unpivot_def) +{ + int ret = OB_SUCCESS; + unpivot_def.set_include_nulls(2 == transpose_node.value_); + if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_4_3_5_2) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unpivot is not supported during updating", K(ret)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "unpivot is not supported during updating"); + + //unpivot column (value column) + } else if (OB_FAIL(resolve_column_names(*transpose_node.children_[0], + unpivot_def.value_columns_))) { + LOG_WARN("fail to resolve_transpose_columns", K(ret)); + + //unpivot for + } else if (OB_FAIL(resolve_column_names(*transpose_node.children_[1], + unpivot_def.label_columns_))) { + LOG_WARN("fail to resolve_transpose_columns", K(ret)); + + //unpivot in + } else { + const ParseNode &in_node = *transpose_node.children_[2]; + if (OB_UNLIKELY(in_node.type_ != T_UNPIVOT_IN_LIST) + || OB_UNLIKELY(in_node.num_child_ <= 0) + || OB_ISNULL(in_node.children_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("in_node is unexpected", K(in_node.type_), K(in_node.num_child_), + KP(in_node.children_), K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < in_node.num_child_; ++i) { + const ParseNode *column_node = in_node.children_[i]; + UnpivotDef::InPair in_pair; + if (OB_ISNULL(column_node) + || OB_UNLIKELY(column_node->type_ != T_UNPIVOT_IN) + || OB_UNLIKELY(column_node->num_child_ != 2) + || OB_ISNULL(column_node->children_) + || OB_ISNULL(column_node->children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column_node is unexpectedl", KP(column_node), K(ret)); + } else if (OB_FAIL(resolve_columns(*column_node->children_[0], + orig_table_item, + in_pair.column_names_, + in_pair.column_exprs_))) { + LOG_WARN("fail to resolve transpose columns", K(ret)); + } else if (OB_UNLIKELY(in_pair.column_names_.count() != unpivot_def.value_columns_.count())) { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("unpivot column count is not match for in column count", K(unpivot_def), + K(in_pair), K(ret)); + } else if (NULL != column_node->children_[1]) { + if (OB_FAIL(resolve_const_exprs(*column_node->children_[1], in_pair.const_exprs_))) { + LOG_WARN("fail to resolve_const_exprs", K(ret)); + } else if (OB_UNLIKELY(in_pair.const_exprs_.count() != unpivot_def.label_columns_.count())){ + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("in column count is not match in literal count", K(unpivot_def), K(in_pair), K(ret)); + } + } else { + // 根据in_pair的名字拼凑一个name作为const_expr + ObString name; + ObConstRawExpr *const_expr = NULL; + if (OB_FAIL(get_combine_name(in_pair.column_names_, name))) { + LOG_WARN("failed to get combine name", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_const_string_expr( + *cur_resolver_->params_.expr_factory_, ObVarcharType, + name, + cur_resolver_->params_.session_info_->get_nls_collation(), + const_expr))) { + LOG_WARN("failed to build const string expr", K(ret)); + } else if (OB_ISNULL(const_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("const expr is null", K(ret)); + } else { + const_expr->set_length(name.length()); + const_expr->set_length_semantics(cur_resolver_->params_.session_info_->get_local_nls_length_semantics()); + } + for (int64_t i = 0; OB_SUCC(ret) && i < unpivot_def.label_columns_.count(); ++i) { + if (OB_FAIL(in_pair.const_exprs_.push_back(const_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + } + if (OB_SUCC(ret) && OB_FAIL(unpivot_def.in_pairs_.push_back(in_pair))) { + LOG_WARN("fail to push_back in_pair", K(in_pair), K(ret)); + } + }//end of for in node + } + }//end of in + return ret; +} + +int ObTransposeResolver::check_pivot_aggr_expr(ObRawExpr *expr) const +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("aggr expr_ is unexpected", KPC(expr), K(ret)); + } else if (!expr->is_aggr_expr()) { + ret = OB_ERR_EXPECT_AGGREGATE_FUNCTION_INSIDE_PIVOT_OPERATION; + LOG_WARN("expect aggregate function inside pivot operation", KPC(expr), K(ret)); + } else if (static_cast(expr)->get_real_param_count() > 2 || + static_cast(expr)->get_order_items().count() > 0) { + ret = OB_ERR_EXPECT_AGGREGATE_FUNCTION_INSIDE_PIVOT_OPERATION; + LOG_WARN("not support aggregation type in pivot", K(ret), K(expr->get_expr_type())); + } else { + // white list + switch (expr->get_expr_type()) { + case T_FUN_COUNT: + case T_FUN_MAX: + case T_FUN_MIN: + case T_FUN_AVG: + case T_FUN_SUM: + case T_FUN_COUNT_SUM: + case T_FUN_APPROX_COUNT_DISTINCT: + case T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS: + case T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE: + case T_FUN_GROUP_CONCAT: + case T_FUN_MEDIAN: + case T_FUN_JSON_ARRAYAGG: + case T_FUN_ORA_JSON_ARRAYAGG: + case T_FUN_JSON_OBJECTAGG: + case T_FUN_ORA_JSON_OBJECTAGG: + case T_FUN_ORA_XMLAGG: + case T_FUN_STDDEV: + case T_FUN_VARIANCE: { + break; + } + default: { + ret = OB_ERR_EXPECT_AGGREGATE_FUNCTION_INSIDE_PIVOT_OPERATION; + LOG_WARN("expect aggregate function inside pivot operation", KPC(expr), K(ret)); + } + } + } + return ret; +} + +int ObTransposeResolver::resolve_columns(const ParseNode &column_node, + TableItem &table_item, + ObIArray &column_names, + ObIArray &columns) +{ + int ret = OB_SUCCESS; + ColumnItem *column_item = NULL; + columns.reuse(); + if (OB_FAIL(resolve_column_names(column_node, column_names))) { + LOG_WARN("failed to resolve column names", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < column_names.count(); ++i) { + if (OB_FAIL(resolve_table_column_item(table_item, column_names.at(i), column_item))) { + LOG_WARN("failed to resolve single table column item", K(ret)); + } else if (OB_ISNULL(column_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if(OB_FAIL(columns.push_back(column_item->get_expr()))) { + LOG_WARN("failed to push back", K(ret)); + } + } + return ret; +} + +int ObTransposeResolver::resolve_column_names(const ParseNode &column_node, ObIArray &columns) +{ + int ret = OB_SUCCESS; + if (column_node.type_ == T_COLUMN_LIST) { + if (OB_UNLIKELY(column_node.num_child_ <= 0) + || OB_ISNULL(column_node.children_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column_node is unexpected", K(column_node.num_child_), + KP(column_node.children_), K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < column_node.num_child_; ++i) { + const ParseNode *tmp_node = column_node.children_[i]; + if (OB_ISNULL(tmp_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column_node is unexpected", KP(tmp_node), K(ret)); + } else { + ObString column_name_(tmp_node->str_len_, tmp_node->str_value_); + if (OB_FAIL(columns.push_back(column_name_))) { + LOG_WARN("fail to push_back column_name_", K(column_name_), K(ret)); + } + } + } + } + } else { + ObString column_name(column_node.str_len_, column_node.str_value_); + if (OB_FAIL(columns.push_back(column_name))) { + LOG_WARN("fail to push_back column_name", K(column_name), K(ret)); + } + } + return ret; +} + +int ObTransposeResolver::resolve_const_exprs( + const ParseNode &expr_node, + ObIArray &const_exprs) +{ + int ret = OB_SUCCESS; + ObRawExpr *const_expr = NULL; + if (expr_node.type_ == T_EXPR_LIST) { + for (int64_t i = 0; OB_SUCC(ret) && i < expr_node.num_child_; ++i) { + const ParseNode *tmp_node = expr_node.children_[i]; + const_expr = NULL; + if (OB_ISNULL(tmp_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("tmp_node is unexpected", KP(tmp_node), K(ret)); + } else if (OB_FAIL(cur_resolver_->resolve_sql_expr(*tmp_node, const_expr))) { + LOG_WARN("fail to resolve_sql_expr", K(ret)); + } else if (OB_UNLIKELY(!const_expr->is_const_expr()) + || OB_UNLIKELY(const_expr->has_flag(ObExprInfoFlag::CNT_CUR_TIME))) { + ret = OB_ERR_NON_CONST_EXPR_IS_NOT_ALLOWED_FOR_PIVOT_UNPIVOT_VALUES; + LOG_WARN("non-constant expression is not allowed for pivot|unpivot values", + KPC(const_expr), K(ret)); + } else if (OB_FAIL(const_exprs.push_back(const_expr))) { + LOG_WARN("fail to push_back const_expr", KPC(const_expr), K(ret)); + } + } + } else { + if (OB_FAIL(cur_resolver_->resolve_sql_expr(expr_node, const_expr))) { + LOG_WARN("fail to resolve_sql_expr", K(ret)); + } else if (OB_UNLIKELY(!const_expr->is_const_expr()) + || OB_UNLIKELY(const_expr->has_flag(ObExprInfoFlag::CNT_CUR_TIME))) { + ret = OB_ERR_NON_CONST_EXPR_IS_NOT_ALLOWED_FOR_PIVOT_UNPIVOT_VALUES; + LOG_WARN("non-constant expression is not allowed for pivot|unpivot values", + KPC(const_expr), K(ret)); + } else if (OB_FAIL(const_exprs.push_back(const_expr))) { + LOG_WARN("fail to push_back const_expr", KPC(const_expr), K(ret)); + } + } + return ret; +} + +int ObTransposeResolver::resolve_table_column_item(const TableItem &table_item, + ObString &column_name, + ColumnItem *&column_item) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(cur_resolver_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (table_item.is_joined_table()) { + const JoinedTable &joined_table = static_cast(table_item); + ColumnItem *left_column_item = NULL; + ColumnItem *right_column_item = NULL; + if (OB_ISNULL(joined_table.left_table_) || OB_ISNULL(joined_table.right_table_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else { + if (OB_SUCC(ret) && OB_FAIL(SMART_CALL(resolve_table_column_item( + *joined_table.left_table_, column_name, left_column_item)))) { + if (ret == OB_ERR_BAD_FIELD_ERROR) { + left_column_item = NULL; + ret = OB_SUCCESS; + } + } + if (OB_SUCC(ret) && OB_FAIL(SMART_CALL(resolve_table_column_item( + *joined_table.right_table_, column_name, right_column_item)))) { + if (ret == OB_ERR_BAD_FIELD_ERROR) { + right_column_item = NULL; + ret = OB_SUCCESS; + } + } + if (OB_FAIL(ret)) { + } else if (left_column_item == NULL && right_column_item == NULL) { + ret = OB_ERR_BAD_FIELD_ERROR; + LOG_WARN("not found column in joined table", K(ret), K(column_name)); + } else if (left_column_item != NULL && right_column_item != NULL) { + ret = OB_NON_UNIQ_ERROR; + LOG_WARN("column in joined tables is ambiguous", K(column_name)); + } else if (left_column_item != NULL) { + column_item = left_column_item; + } else { + column_item = right_column_item; + } + } + } else if (OB_FAIL(cur_resolver_->resolve_single_table_column_item( + table_item, column_name, false, column_item))) { + LOG_WARN("failed to resolve single table column item", K(ret), K(table_item)); + } + return ret; +} + +int ObTransposeResolver::resolve_all_table_columns(const TableItem &table_item, + ObIArray &column_items) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(cur_resolver_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(cur_resolver_), K(table_item)); + } else if (table_item.is_basic_table() || table_item.is_fake_cte_table() || table_item.is_link_table()) { + if (OB_FAIL(cur_resolver_->resolve_all_basic_table_columns(table_item, false, &column_items))) { + LOG_WARN("resolve all basic table columns failed", K(ret)); + } + } else if (table_item.is_generated_table() || table_item.is_temp_table()) { + if (OB_FAIL(cur_resolver_->resolve_all_generated_table_columns(table_item, column_items))) { + LOG_WARN("resolve all generated table columns failed", K(ret)); + } + } else if (table_item.is_joined_table()) { + const JoinedTable &joined_table = static_cast (table_item); + if (OB_ISNULL(joined_table.left_table_) || OB_ISNULL(joined_table.right_table_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret)); + } else if (OB_FAIL(SMART_CALL(resolve_all_table_columns(*joined_table.left_table_, column_items)))) { + LOG_WARN("failed to resolve columns for left table of joined table", K(ret)); + } else if (OB_FAIL(SMART_CALL(resolve_all_table_columns(*joined_table.right_table_, column_items)))) { + LOG_WARN("failed to resolve columns for right table of joined table", K(ret)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("not support this table", K(table_item), K(ret)); + } + return ret; +} + +int ObTransposeResolver::get_old_or_group_column( + const ObIArray &columns_in_aggrs, + TableItem &orig_table_item, + TransposeDef &trans_def) +{ + int ret = OB_SUCCESS; + //1.get columns + ObSEArray column_items; + if (OB_FAIL(resolve_all_table_columns(orig_table_item, column_items))) { + LOG_WARN("failed to resolve all table columns", K(ret)); + } + + // 2. get group/old column + if (trans_def.is_pivot()) { + PivotDef &pivot_def = static_cast (trans_def); + if (OB_FAIL(remove_column_item_by_names(column_items, columns_in_aggrs))) { + LOG_WARN("failed to remove column item by name", K(ret)); + } else if (OB_FAIL(remove_column_item_by_names(column_items, pivot_def.for_column_names_))) { + LOG_WARN("failed to remove column item by name", K(ret)); + } + pivot_def.group_columns_.reuse(); + for (int64_t i = 0; OB_SUCC(ret) && i < column_items.count(); ++i) { + ObColumnRefRawExpr *col_ref_expr = column_items.at(i).get_expr(); + if (OB_ISNULL(col_ref_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("col_ref_expr is null", K(ret)); + } else if (OB_FAIL(col_ref_expr->set_expr_name(col_ref_expr->get_column_name()))) { + LOG_WARN("failed to set expr name", K(ret)); + } else if (OB_FAIL(pivot_def.group_columns_.push_back(col_ref_expr)) || + OB_FAIL(pivot_def.group_column_names_.push_back(col_ref_expr->get_column_name()))) { + LOG_WARN("failed to push back", K(ret)); + } else if (ObUserDefinedSQLType == col_ref_expr->get_data_type()) { + ret = OB_ERR_NO_ORDER_MAP_SQL; + LOG_WARN("cannot ORDER objects without MAP or ORDER method", K(ret)); + } else if (ObLongTextType == col_ref_expr->get_data_type() + || ObLobType == col_ref_expr->get_data_type() + || ObJsonType == col_ref_expr->get_data_type() + || ObGeometryType == col_ref_expr->get_data_type() + || ObExtendType == col_ref_expr->get_data_type()) { + ret = (lib::is_oracle_mode() && ObJsonType == col_ref_expr->get_data_type()) + ? OB_ERR_INVALID_CMP_OP : OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("group by lob expr is not allowed", K(ret)); + } + } + } else { + UnpivotDef &unpivot_def = static_cast (trans_def); + for (int64_t i = 0; OB_SUCC(ret) && i < unpivot_def.in_pairs_.count(); ++i) { + const common::ObIArray &in_columns = unpivot_def.in_pairs_.at(i).column_names_; + if (OB_FAIL(remove_column_item_by_names(column_items, in_columns))) { + LOG_WARN("failed to remove column item by name", K(ret)); + } + } + unpivot_def.orig_columns_.reuse(); + for (int64_t i = 0; OB_SUCC(ret) && i < column_items.count(); ++i) { + ObColumnRefRawExpr *col_ref_expr = column_items.at(i).get_expr(); + if (OB_ISNULL(col_ref_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("col_ref_expr is null", K(ret)); + } else if (OB_FAIL(col_ref_expr->set_expr_name(col_ref_expr->get_column_name()))) { + LOG_WARN("failed to set expr name", K(ret)); + } else if (OB_FAIL(unpivot_def.orig_columns_.push_back(col_ref_expr)) || + OB_FAIL(unpivot_def.orig_column_names_.push_back(col_ref_expr->get_column_name()))) { + LOG_WARN("failed to push back", K(ret)); + } + } + } + return ret; +} + +int ObTransposeResolver::try_add_cast_to_unpivot(UnpivotDef &unpivot_def) +{ + int ret = OB_SUCCESS; + ObSEArray left_types; + ObSEArray tmp_types; + ObSEArray res_types; + // get types + for (int64_t i = 0; OB_SUCC(ret) && i < unpivot_def.in_pairs_.count(); ++i) { + UnpivotDef::InPair &in_pair = unpivot_def.in_pairs_.at(i); + tmp_types.reuse(); + for (int64_t j = 0; OB_SUCC(ret) && j < in_pair.const_exprs_.count(); ++j) { + if (OB_ISNULL(in_pair.const_exprs_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(tmp_types.push_back(in_pair.const_exprs_.at(j)->get_result_type()))) { + LOG_WARN("failed to push back", K(ret)); + } + } + for (int64_t j = 0; OB_SUCC(ret) && j < in_pair.column_exprs_.count(); ++j) { + if (OB_ISNULL(in_pair.column_exprs_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(tmp_types.push_back(in_pair.column_exprs_.at(j)->get_result_type()))) { + LOG_WARN("failed to push back", K(ret)); + } + } + if (i == 0) { + if (OB_FAIL(left_types.assign(tmp_types))) { + LOG_WARN("failed to assign", K(ret)); + } + } else { + if (OB_FAIL(get_merge_type_for_unpivot(left_types, tmp_types, res_types))) { + LOG_WARN("invalid types", K(ret)); + } else if (OB_FAIL(left_types.assign(res_types))) { + LOG_WARN("failed to assign", K(ret)); + } + } + } + + // add cast + for (int64_t i = 0; OB_SUCC(ret) && i < unpivot_def.in_pairs_.count(); ++i) { + ObRawExpr *casted_expr = NULL; + UnpivotDef::InPair &in_pair = unpivot_def.in_pairs_.at(i); + tmp_types.reuse(); + for (int64_t j = 0; OB_SUCC(ret) && j < in_pair.const_exprs_.count(); ++j) { + if (OB_ISNULL(in_pair.const_exprs_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(cur_resolver_->params_.expr_factory_, + cur_resolver_->params_.session_info_, + *in_pair.const_exprs_.at(j), + res_types.at(j), + casted_expr))) { + LOG_WARN("failed to try add cast expr", K(ret)); + } else if (OB_ISNULL(casted_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else { + in_pair.const_exprs_.at(j) = casted_expr; + } + } + for (int64_t j = 0; OB_SUCC(ret) && j < in_pair.column_exprs_.count(); ++j) { + if (OB_ISNULL(in_pair.column_exprs_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above(cur_resolver_->params_.expr_factory_, + cur_resolver_->params_.session_info_, + *in_pair.column_exprs_.at(j), + res_types.at(in_pair.const_exprs_.count() + j), + casted_expr))) { + LOG_WARN("failed to push back", K(ret)); + } else if (OB_ISNULL(casted_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else { + in_pair.column_exprs_.at(j) = casted_expr; + } + } + } + return ret; +} + +int ObTransposeResolver::get_merge_type_for_unpivot(ObIArray &left_types, + ObIArray &right_types, + ObIArray &res_types) +{ + int ret = OB_SUCCESS; + ObExprResType res_type; + ObIAllocator *allocator = NULL; + ObSQLSessionInfo *session_info = NULL; + if (OB_ISNULL(cur_resolver_) || + OB_ISNULL(allocator = cur_resolver_->params_.allocator_) || + OB_ISNULL(session_info = cur_resolver_->params_.session_info_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("params is null", K(ret)); + } else if (OB_UNLIKELY(left_types.count() != right_types.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("count of left types and right types not equal", K(ret)); + } else { + res_types.reuse(); + const int64_t num = left_types.count(); + for (int64_t i = 0; OB_SUCC(ret) && i < num; i++) { + res_type.reset(); + ObExprResType &left_type = left_types.at(i); + ObExprResType &right_type = right_types.at(i); + if (!left_type.has_result_flag(NOT_NULL_FLAG) || !right_type.has_result_flag(NOT_NULL_FLAG)) { + left_type.unset_result_flag(NOT_NULL_FLAG); + right_type.unset_result_flag(NOT_NULL_FLAG); + } + if (left_type != right_type || ob_is_enumset_tc(right_type.get_type())) { + ObSEArray types; + ObExprVersion dummy_op(*allocator); + ObCollationType coll_type = CS_TYPE_INVALID; + ObExprTypeCtx type_ctx; + ObSQLUtils::init_type_ctx(session_info, type_ctx); + bool skip_add_cast = false; + if (lib::is_oracle_mode()) { + if (OB_FAIL(ObOptimizerUtil::check_oracle_mode_set_type_validity( + session_info->is_varparams_sql_prepare(), left_type, right_type, false, &skip_add_cast))) { + LOG_WARN("left and right type of set operator not valid in oracle mode", K(ret)); + } + LOG_DEBUG("data type check for each select item in set operator", K(left_type), + K(right_type)); + } + if (OB_FAIL(ret)) { + } else if (skip_add_cast) { + res_type = left_type; + } else if (OB_FAIL(types.push_back(left_type)) || OB_FAIL(types.push_back(right_type))) { + LOG_WARN("failed to push back", K(ret)); + } else if (OB_FAIL(dummy_op.aggregate_result_type_for_merge(res_type, &types.at(0), 2, + is_oracle_mode(), type_ctx))) { + if (session_info->is_varparams_sql_prepare()) { + skip_add_cast = true; + res_type = left_type; + LOG_WARN("failed to deduce type in ps prepare stage", K(types)); + } else { + LOG_WARN("failed to aggregate result type for merge", K(ret)); + } + } + if (OB_FAIL(ret) || skip_add_cast) { + } else if (ObMaxType == res_type.get_type()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("column type incompatible", K(left_type), K(right_type)); + } else if ((left_type.is_ext() && !right_type.is_ext()) || + (!left_type.is_ext() && right_type.is_ext()) || + (left_type.is_ext() && right_type.is_ext() && + left_type.get_udt_id() != right_type.get_udt_id())) { + ret = OB_ERR_EXP_NEED_SAME_DATATYPE; + LOG_WARN("expression must have same datatype as corresponding expression", K(ret), K(left_type), K(right_type)); + } + } else { + res_type = left_type; + } + if (OB_SUCC(ret) && OB_FAIL(res_types.push_back(res_type))) { + LOG_WARN("failed to push back res type", K(ret)); + } + } + } + return ret; +} + +int ObTransposeResolver::transform_to_view(TableItem &orig_table_item, + TransposeDef &trans_def, + TableItem *&view_table) +{ + int ret = OB_SUCCESS; + ObSEArray select_exprs; + ObSEArray condition_exprs; + ObSEArray group_exprs; + ObSEArray *group_exprs_ptr = NULL; + ObSEArray old_table_cols; + ObSEArray new_table_cols; + if (trans_def.is_pivot()) { + if (OB_FAIL(get_exprs_for_pivot_table(static_cast(trans_def), select_exprs, group_exprs))) { + LOG_WARN("failed to build inline view for pivot", K(ret)); + } else { + group_exprs_ptr = &group_exprs; + } + } else /* unpivot */ { + if (OB_FAIL(get_exprs_for_unpivot_table(static_cast(trans_def), select_exprs, condition_exprs))) { + LOG_WARN("failed to build inline view for unpivot", K(ret)); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(add_new_table_item(view_table, trans_def.alias_name_))) { + LOG_WARN("failed to replace with empty view", K(ret)); + } else if (OB_FAIL(push_transpose_table_into_view(view_table, + &orig_table_item, + trans_def, + select_exprs, + condition_exprs, + group_exprs_ptr))) { + LOG_WARN("failed to push transpose table into view", K(ret)); + } else if (OB_UNLIKELY(!view_table->is_generated_table()) || + OB_ISNULL(view_table->ref_query_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected view table", K(ret), K(*view_table)); + } + return ret; +} + +int ObTransposeResolver::get_exprs_for_pivot_table(PivotDef &pivot_def, + ObIArray &select_exprs, + ObIArray &group_exprs) +{ + int ret = OB_SUCCESS; + // get group columns + ObIArray &groups = pivot_def.group_columns_; + for (int64_t i = 0; OB_SUCC(ret) && i < groups.count(); ++i) { + if (OB_FAIL(select_exprs.push_back(groups.at(i))) || + OB_FAIL(group_exprs.push_back(groups.at(i)))) { + LOG_WARN("failed to push back", K(ret)); + } + } + // get other select exprs + for (int64_t i = 0; OB_SUCC(ret) && i < pivot_def.in_pairs_.count(); ++i) { + PivotDef::InPair in_pair = pivot_def.in_pairs_.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < pivot_def.aggr_pairs_.count(); ++j) { + PivotDef::AggrPair &aggr_pair = pivot_def.aggr_pairs_.at(j); + ObRawExpr *select_expr = NULL; + if (OB_FAIL(build_select_expr_for_pivot(aggr_pair, in_pair, pivot_def.for_columns_, select_expr))) { + LOG_WARN("failed to build select expr for pivot", K(ret)); + } else if (OB_ISNULL(select_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("select_expr is null", K(ret)); + } else if (OB_FAIL(select_exprs.push_back(select_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + } + return ret; +} + +// aggr(expr) -> aggr(case when (for_exprs) in (in_exprs) then expr end) +// count(*) -> count(case when (for_exprs) in (in_exprs) then 1 end) +// list_agg(expr1, expr2) -> list_agg(case when (for_exprs) in (in_exprs) then expr1 end, expr2) +// ((c1, c2) in (1, 2)) is in fact (c1=1 and c2=2), so 'for_exprs in in_exprs' is 'for_expr1 = in_expr2 and ...' +int ObTransposeResolver::build_select_expr_for_pivot( + PivotDef::AggrPair &aggr_pair, + PivotDef::InPair &in_pair, + ObIArray &for_exprs, + ObRawExpr *&select_expr) +{ + int ret = OB_SUCCESS; + ObRawExprFactory *expr_factory = NULL; + ObSQLSessionInfo *session_info = NULL; + if (OB_ISNULL(cur_resolver_) || + OB_ISNULL(expr_factory = cur_resolver_->params_.expr_factory_) || + OB_ISNULL(session_info = cur_resolver_->params_.session_info_) || + OB_ISNULL(aggr_pair.expr_) || + OB_UNLIKELY(for_exprs.count() != in_pair.const_exprs_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null or invalid expr_exprs and in_pair", K(ret)); + } else { + ObSEArray param_exprs; + ObSEArray new_param_exprs; + ObAggFunRawExpr *ori_aggr_expr = static_cast (aggr_pair.expr_); + ObAggFunRawExpr *aggr_expr = NULL; + ObRawExpr *when_expr = NULL; + ObRawExpr *null_expr = NULL; + ObSEArray equal_exprs; + if (ori_aggr_expr->get_real_param_count() == 0) /* count(*) */ { + ObConstRawExpr *const_expr = NULL; + if (OB_FAIL(ObRawExprUtils::build_const_int_expr(*expr_factory, ObIntType, 1, const_expr))) { + LOG_WARN("failed to build const expr 1", K(ret)); + } else if (OB_FAIL(param_exprs.push_back(const_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } else { + if (OB_FAIL(param_exprs.assign(ori_aggr_expr->get_real_param_exprs()))) { + LOG_WARN("failed to assign", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(expr_factory->create_raw_expr(aggr_pair.expr_->get_expr_type(), aggr_expr))) { + LOG_WARN("failed to create raw expr", K(ret)); + } else if (OB_ISNULL(aggr_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(aggr_expr->assign(*aggr_pair.expr_))) { + LOG_WARN("failed to assign aggr expr", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < for_exprs.count(); ++i) { + ObRawExpr *equal_expr = NULL; + if (OB_FAIL(ObRawExprUtils::create_equal_expr(*expr_factory, + session_info, + in_pair.const_exprs_.at(i), + for_exprs.at(i), + equal_expr))) { + LOG_WARN("failed to create equal expr", K(ret)); + } else if (OB_ISNULL(equal_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(equal_exprs.push_back(equal_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObRawExprUtils::build_and_expr(*expr_factory, + equal_exprs, + when_expr))) { + LOG_WARN("failed to build and expr", K(ret)); + } else if (OB_ISNULL(when_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (ObRawExprUtils::build_null_expr(*expr_factory, null_expr)) { + LOG_WARN("failed to build null expr", K(ret)); + } else if (OB_ISNULL(null_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < param_exprs.count(); ++i) { + ObRawExpr *case_expr = NULL; + if (OB_ISNULL(param_exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (ObRawExprUtils::build_case_when_expr(*expr_factory, + when_expr /*when expr*/, + param_exprs.at(i)/*then expr*/, + null_expr /*default_expr*/, + case_expr)) { + LOG_WARN("failed to build case when expr", K(ret)); + } else if (OB_ISNULL(case_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(new_param_exprs.push_back(case_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + if (FAILEDx(aggr_expr->get_real_param_exprs_for_update().assign(new_param_exprs))) { + LOG_WARN("failed to assign", K(ret)); + } else { + select_expr = aggr_expr; + } + } + + if (OB_SUCC(ret)) { + ObSqlString comb_name; + ObString name_string; + if (aggr_pair.alias_name_.empty()) { + // in_pair name + if (OB_FAIL(comb_name.append(in_pair.name_))) { + LOG_WARN("failed to append", K(ret)); + } + } else { + // aggr_name + '_' + in_pair_name + if (OB_FAIL(comb_name.append(in_pair.name_)) || + OB_FAIL(comb_name.append("_")) || + OB_FAIL(comb_name.append(aggr_pair.alias_name_))) { + LOG_WARN("failed to append", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ob_write_string(*cur_resolver_->params_.allocator_, comb_name.string(), name_string))) { + LOG_WARN("failed to write string", K(ret)); + } else if (OB_FAIL(select_expr->set_expr_name(name_string))) { + LOG_WARN("failed to set expr name", K(ret)); + } + } + return ret; +} + +int ObTransposeResolver::get_exprs_for_unpivot_table(UnpivotDef &trans_def, + ObIArray &select_exprs, + ObIArray &condition_exprs) +{ + int ret = OB_SUCCESS; + ObRawExprFactory *expr_factory = NULL; + if (OB_ISNULL(cur_resolver_) || + OB_ISNULL(expr_factory = cur_resolver_->params_.expr_factory_) || + OB_UNLIKELY(!trans_def.is_unpivot()) || + OB_UNLIKELY(trans_def.in_pairs_.count() == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid argument or context", K(ret)); + } else { + // old columns (old column expr) + ObIArray &old_columns = trans_def.orig_columns_; + ObSEArray param_exprs; + ObRawExpr *target_expr = NULL; + bool need_unpivot_op = trans_def.in_pairs_.count() > 1; + for (int64_t i = 0; OB_SUCC(ret) && i < old_columns.count(); ++i) { + if (OB_FAIL(select_exprs.push_back(old_columns.at(i)))) { + LOG_WARN("failed to push back", K(ret)); + } + } + // lab columns (unpivot(in_pair.const_exprs)) + for (int64_t i = 0; OB_SUCC(ret) && i < trans_def.label_columns_.count(); ++i) { + param_exprs.reuse(); + for (int64_t j = 0; OB_SUCC(ret) && j < trans_def.in_pairs_.count(); ++j) { + UnpivotDef::InPair &in_pair = trans_def.in_pairs_.at(j); + if (OB_UNLIKELY(in_pair.const_exprs_.count() != trans_def.label_columns_.count()) || + OB_ISNULL(in_pair.const_exprs_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid count or unexpected null", K(ret)); + } else if (OB_FAIL(param_exprs.push_back(in_pair.const_exprs_.at(i)))) { + LOG_WARN("failed to push back", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (need_unpivot_op) { + if (OB_FAIL(ObRawExprUtils::build_unpivot_expr(*expr_factory, param_exprs, target_expr, true))) { + LOG_WARN("failed to build unpivot expr", K(ret)); + } + } else { + target_expr = param_exprs.at(0); + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(target_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unpivot_expr is null", K(ret)); + } else if (OB_FAIL(target_expr->set_expr_name(trans_def.label_columns_.at(i)))) { + LOG_WARN("failed to set expr name", K(ret)); + } else if (OB_FAIL(select_exprs.push_back(target_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + // value column (unpivot(in_pair.column_exprs)) + for (int64_t i = 0; OB_SUCC(ret) && i < trans_def.value_columns_.count(); ++i) { + param_exprs.reuse(); + for (int64_t j = 0; OB_SUCC(ret) && j < trans_def.in_pairs_.count(); ++j) { + UnpivotDef::InPair &in_pair = trans_def.in_pairs_.at(j); + if (OB_UNLIKELY(in_pair.column_exprs_.count() != trans_def.value_columns_.count()) || + OB_ISNULL(in_pair.column_exprs_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid count or unexpected null", K(ret)); + } else if (OB_FAIL(param_exprs.push_back(in_pair.column_exprs_.at(i)))) { + LOG_WARN("failed to push back", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (need_unpivot_op) { + if (OB_FAIL(ObRawExprUtils::build_unpivot_expr(*expr_factory, param_exprs, target_expr, false))) { + LOG_WARN("failed to build unpivot expr", K(ret)); + } + } else { + target_expr = param_exprs.at(0); + if (trans_def.is_exclude_null()) { + ObRawExpr *not_null_expr = NULL; + if (OB_FAIL(ObRawExprUtils::build_is_not_null_expr(*expr_factory, target_expr, true, not_null_expr))) { + LOG_WARN("failed to build is not null expr", K(ret)); + } else if (OB_ISNULL(not_null_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(condition_exprs.push_back(not_null_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(target_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unpivot_expr is null", K(ret)); + } else if (OB_FAIL(target_expr->set_expr_name(trans_def.value_columns_.at(i)))) { + LOG_WARN("failed to set expr name", K(ret)); + } else if (OB_FAIL(select_exprs.push_back(target_expr))) { + LOG_WARN("failed to push back", K(ret)); + } + } + } + return ret; +} + +int ObTransposeResolver::get_unpivot_item(UnpivotDef &unpivot_def, + ObIArray &select_exprs, + ObUnpivotItem *&unpivot_item) +{ + int ret = OB_SUCCESS; + ObIAllocator *allocator = NULL; + void *ptr = NULL; + if (OB_ISNULL(cur_resolver_) || + OB_ISNULL(allocator = cur_resolver_->params_.allocator_) || + OB_UNLIKELY(!unpivot_def.is_unpivot())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected argument", K(ret)); + } else if (unpivot_def.in_pairs_.count() == 1) { + unpivot_item = NULL; + } else if (OB_ISNULL(ptr = allocator->alloc(sizeof(ObUnpivotItem)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("create unpivot info failed"); + } else if (OB_ISNULL(unpivot_item = new (ptr) ObUnpivotItem())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else { + int64_t old_count = unpivot_def.orig_columns_.count(); + int64_t lab_count = unpivot_def.label_columns_.count(); + int64_t val_count = unpivot_def.value_columns_.count(); + unpivot_item->is_include_null_ = unpivot_def.is_include_null(); + if (OB_UNLIKELY(select_exprs.count() != old_count + lab_count + val_count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected argument", K(ret), K(select_exprs), K(old_count), K(lab_count), K(val_count)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < old_count; ++i) { + if (OB_FAIL(unpivot_item->origin_exprs_.push_back(select_exprs.at(i)))) { + LOG_WARN("failed to push back", K(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < lab_count; ++i) { + if (OB_FAIL(unpivot_item->label_exprs_.push_back(select_exprs.at(old_count + i)))) { + LOG_WARN("failed to push back", K(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < val_count; ++i) { + if (OB_FAIL(unpivot_item->value_exprs_.push_back(select_exprs.at(old_count + lab_count + i)))) { + LOG_WARN("failed to push back", K(ret)); + } + } + } + return ret; +} + +int ObTransposeResolver::push_transpose_table_into_view( + TableItem *&view_table, + TableItem *origin_table, + TransposeDef &trans_def, + ObIArray &select_exprs, + ObIArray &conditions, + ObIArray *group_exprs /* = NULL*/) +{ + int ret = OB_SUCCESS; + ObDMLStmt *stmt = NULL; + ObSelectStmt *view_stmt = NULL; + ObRawExprFactory *expr_factory = NULL; + ObIAllocator *allocator = NULL; + ObSEArray basic_table_ids; + + if (OB_ISNULL(cur_resolver_) + || OB_ISNULL(origin_table) + || OB_ISNULL(stmt = cur_resolver_->get_stmt()) + || OB_ISNULL(expr_factory = cur_resolver_->params_.expr_factory_) + || OB_ISNULL(allocator = cur_resolver_->params_.allocator_) + || OB_ISNULL(view_table) + || OB_UNLIKELY(!view_table->is_generated_table()) + || OB_UNLIKELY(NULL != view_table->ref_query_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected params", K(ret), K(stmt)); + } else if (OB_FAIL(cur_resolver_->params_.stmt_factory_->create_stmt(view_stmt))) { + LOG_WARN("failed to create stmt", K(ret)); + } else if (OB_ISNULL(view_stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(view_stmt)); + } else if (OB_FAIL(view_stmt->get_stmt_hint().assign(stmt->get_stmt_hint()))) { + LOG_WARN("failed to set simple view hint", K(ret)); + } else if (FALSE_IT(view_stmt->set_query_ctx(stmt->get_query_ctx()))) { + // never reach + } else if (OB_FAIL(view_stmt->set_stmt_id())) { + LOG_WARN("failed to adjust statement id", K(ret)); + } else { + view_table->ref_query_ = view_stmt; + view_table->table_name_ = trans_def.alias_name_; + view_table->alias_name_ = trans_def.alias_name_; + if (trans_def.is_pivot()) { + view_stmt->set_from_pivot(true); + } else { + ObUnpivotItem *unpivot_item = NULL; + if (OB_FAIL(get_unpivot_item(static_cast(trans_def), select_exprs, unpivot_item))) { + LOG_WARN("failed to get unpivot info", K(ret)); + } else { + view_stmt->set_unpivot_item(unpivot_item); + } + } + } + + // 1. construct view stmt + // 1.1 move from tables + if (OB_SUCC(ret)) { + bool is_joined_table = (NULL != origin_table && origin_table->is_joined_table()); + TableItem *table = origin_table; + if (OB_ISNULL(table)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table is null", K(ret), K(table)); + } else if (OB_FAIL(view_stmt->add_from_item(table->table_id_, is_joined_table))) { + LOG_WARN("failed to add from item", K(ret)); + } else if (is_joined_table) { + if (OB_FAIL(stmt->remove_joined_table_item(table->table_id_))) { + LOG_WARN("failed to remove joined table", K(ret)); + } else if (OB_FAIL(append(basic_table_ids, static_cast(table)->single_table_ids_))) { + LOG_WARN("failed to append single table ids", K(ret)); + } else if (OB_FAIL(view_stmt->add_joined_table(static_cast(table)))) { + LOG_WARN("failed to add joined table", K(ret)); + } + } else if (OB_FAIL(basic_table_ids.push_back(table->table_id_))) { + LOG_WARN("failed to push back table id", K(ret)); + } + } + + for (int64_t i = 0; OB_SUCC(ret) && i < basic_table_ids.count(); ++i) { + uint64_t table_id = basic_table_ids.at(i); + TableItem *table = NULL; + ObArray column_items; + ObArray part_expr_items; + CheckConstraintItem check_constraint_item; + if (OB_ISNULL(table = stmt->get_table_item_by_id(table_id))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table is null", K(ret), K(table)); + } else if (OB_FAIL(stmt->get_column_items(table_id, column_items))) { + LOG_WARN("failed to get column items", K(ret)); + } else if (OB_FAIL(stmt->get_part_expr_items(table_id, part_expr_items))) { + LOG_WARN("failed to get part expr items", K(ret)); + } else if (OB_FAIL(stmt->get_check_constraint_items(table_id, check_constraint_item))) { + LOG_WARN("failed to get check constraint item", K(ret)); + } else if (OB_FAIL(view_stmt->get_table_items().push_back(table))) { + LOG_WARN("failed to add table item", K(ret)); + } else if (OB_FAIL(append(view_stmt->get_column_items(), column_items))) { + LOG_WARN("failed to add column items", K(ret)); + } else if (OB_FAIL(view_stmt->set_part_expr_items(part_expr_items))) { + LOG_WARN("failed to set part expr items", K(ret)); + } else if (OB_FAIL(view_stmt->set_check_constraint_item(check_constraint_item))) { + LOG_WARN("failed to add check constraint items", K(ret)); + } else if (OB_FAIL(stmt->remove_table_item(table))) { + LOG_WARN("failed to remove table item", K(ret)); + } else if (OB_FAIL(stmt->remove_column_item(basic_table_ids.at(i)))) { + LOG_WARN("failed to remove column item", K(ret)); + } else if (OB_FAIL(stmt->remove_part_expr_items(basic_table_ids.at(i)))) { + LOG_WARN("failed to remove part expr items", K(ret)); + } else if (OB_FAIL(stmt->remove_check_constraint_item(basic_table_ids.at(i)))) { + LOG_WARN("failed to remove check constraint item", K(ret)); + } + } + + // 2 construct group exprs. + if (OB_FAIL(ret)) { + } else if ( OB_FAIL(view_stmt->get_condition_exprs().assign(conditions))) { + LOG_WARN("failed to assign conditions", K(ret)); + } else if (NULL != group_exprs && + OB_FAIL(view_stmt->get_group_exprs().assign(*group_exprs))) { + LOG_WARN("failed to assign group exprs", K(ret)); + + // 3 extract aggr and winfun + } else if (OB_FAIL(ObTransformUtils::extract_aggr_expr(select_exprs, view_stmt->get_aggr_items()))) { + LOG_WARN("failed to extract aggr expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::extract_winfun_expr(select_exprs, view_stmt->get_window_func_exprs()))) { + LOG_WARN("failed to extract aggr expr", K(ret)); + + // 4 generate select list and adjust structures + } else if (OB_FAIL(view_stmt->rebuild_tables_hash())) { + LOG_WARN("failed to rebuild table hash", K(ret)); + } else if (OB_FAIL(view_stmt->update_column_item_rel_id())) { + LOG_WARN("failed to update column item by id", K(ret)); + } else if (OB_FAIL(generate_select_list(view_table, select_exprs))) { + LOG_WARN("failed to generate select list", K(ret)); + } else if ((stmt->is_delete_stmt() || stmt->is_update_stmt() || stmt->is_merge_stmt()) && + OB_FAIL(ObTransformUtils::adjust_updatable_view(*expr_factory, + static_cast(stmt), + *view_table, + &basic_table_ids))) { + LOG_WARN("failed to adjust updatable view", K(ret)); + } else if (OB_FAIL(stmt->rebuild_tables_hash())) { + LOG_WARN("failed to rebuild table hash", K(ret)); + } else if (OB_FAIL(stmt->update_column_item_rel_id())) { + LOG_WARN("failed to update column item by id", K(ret)); + } else if (OB_FAIL(stmt->formalize_stmt(cur_resolver_->params_.session_info_))) { + LOG_WARN("failed to formalize stmt", K(ret)); + } else { + if (view_stmt->has_for_update() && lib::is_oracle_mode()) { + view_table->for_update_ = true; + } + } + if (OB_SUCC(ret) && stmt->is_select_stmt()) { + //check qualify filters + if (OB_FAIL(ObTransformUtils::pushdown_qualify_filters(static_cast(stmt)))) { + LOG_WARN("check pushdown qualify filters failed", K(ret)); + } + } + return ret; +} + +int ObTransposeResolver::add_new_table_item(TableItem *&view_table, const ObString &alias_name) +{ + int ret = OB_SUCCESS; + TableItem *table_item = NULL; + ObIAllocator *allocator = NULL; + ObDMLStmt *stmt = NULL; + if (OB_ISNULL(cur_resolver_) || + OB_ISNULL(stmt = cur_resolver_->get_stmt()) || + OB_ISNULL(allocator = cur_resolver_->params_.allocator_) || + OB_ISNULL(stmt->get_query_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to add new table_item because some value is null", K(ret)); + } else if (OB_ISNULL(table_item = stmt->create_table_item(*allocator))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("create table item failed"); + } else { + table_item->table_id_ = stmt->get_query_ctx()->available_tb_id_--; + table_item->type_ = TableItem::GENERATED_TABLE; + table_item->ref_id_ = OB_INVALID_ID; + table_item->database_name_ = ObString::make_string(""); + table_item->table_name_ = alias_name; + table_item->alias_name_ = alias_name; + table_item->ref_query_ = NULL; + if (OB_FAIL(stmt->set_table_bit_index(table_item->table_id_))) { + LOG_WARN("fail to add table_id to hash table", K(ret), K(table_item)); + } else if (OB_FAIL(stmt->get_table_items().push_back(table_item))) { + LOG_WARN("add table item failed", K(ret)); + } else { + view_table = table_item; + } + } + return ret; +} + +// copied from ObTransformUtils +int ObTransposeResolver::generate_select_list(TableItem *table, + ObIArray &basic_select_exprs) +{ + int ret = OB_SUCCESS; + ObDMLStmt *stmt = NULL; + ObSelectStmt *view_stmt = NULL; + ObRawExprFactory *expr_factory = NULL; + ObArray shared_exprs; + ObArray column_exprs; + ObArray select_exprs; + if (OB_ISNULL(cur_resolver_) || OB_ISNULL(stmt = cur_resolver_->get_stmt()) || + OB_ISNULL(table) || OB_ISNULL(expr_factory = cur_resolver_->params_.expr_factory_) || + OB_UNLIKELY(!table->is_generated_table()) || + OB_ISNULL(view_stmt = table->ref_query_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("params have null", K(ret), K(stmt), KPC(table)); + } else if (OB_FAIL(select_exprs.assign(basic_select_exprs))) { + LOG_WARN("failed to assign", K(ret)); + // The shared child exprs of basic_select_exprs should be extracted + } else if (OB_FAIL(ObTransformUtils::extract_shared_exprs(stmt, view_stmt, shared_exprs, &basic_select_exprs))) { + LOG_WARN("failed to extract shared expr", K(ret)); + } else if (OB_FAIL(ObTransformUtils::remove_const_exprs(shared_exprs, shared_exprs))) { + LOG_WARN("failed to remove const exprs", K(ret)); + } else if (OB_FAIL(append(select_exprs, shared_exprs))) { + LOG_WARN("failed to append", K(ret)); + } else if (select_exprs.empty()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param", K(ret)); + } else if (OB_FAIL(ObTransformUtils::create_select_item( + *cur_resolver_->params_.allocator_, select_exprs, view_stmt))) { + LOG_WARN("failed to create select items", K(ret)); + } + + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(*stmt))) { + LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); + } else if (OB_FAIL(ObTransformUtils::adjust_pseudo_column_like_exprs(*view_stmt))) { + LOG_WARN("failed to adjust pseudo column like exprs", K(ret)); + } + return ret; +} + +int ObTransposeResolver::get_column_item_idx_by_name( + ObIArray &array, + const ObString &var, + int64_t &idx) +{ + int ret = OB_SUCCESS; + idx = OB_INVALID_INDEX; + const int64_t num = array.count(); + for (int64_t i = 0; i < num; i++) { + if (var == array.at(i).column_name_) { + idx = i; + break; + } + } + return ret; +} + +int ObTransposeResolver::remove_column_item_by_names( + ObIArray &column_items, + const ObIArray &names) +{ + int ret = OB_SUCCESS; + int64_t idx = OB_INVALID_INDEX; + for (int64_t i = 0; OB_SUCC(ret) && i < names.count(); ++i) { + const ObString &name = names.at(i); + if (OB_FAIL(get_column_item_idx_by_name(column_items, name, idx))) { + LOG_WARN("fail to get_column_item_idx_by_name", K(name), K(ret)); + } else if (idx >= 0) { + if (OB_FAIL(column_items.remove(idx))) { + LOG_WARN("fail to remove column_item", K(idx), K(ret)); + } + } + } + return ret; +} + +int ObTransposeResolver::get_combine_name(ObIArray &names, ObString &comb_name) { + int ret = OB_SUCCESS; + ObIAllocator *allocator = NULL; + ObSqlString str; + char name_buf[OB_MAX_COLUMN_NAME_LENGTH]; + int64_t pos = 0; + if (OB_ISNULL(cur_resolver_) || + OB_ISNULL(allocator = cur_resolver_->params_.allocator_) || + OB_UNLIKELY(names.count() == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid argument", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < names.count(); ++i) { + ObString name = names.at(i); + if (OB_UNLIKELY(name.empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(str.append_fmt("%.*s_", name.length(), name.ptr()))) { + LOG_WARN("failed to append fmt", K(ret)); + } + } + if (OB_SUCC(ret)) { + char *buf = NULL; + if (OB_ISNULL(buf = static_cast(allocator->alloc(str.length() - 1)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("no more memory to create in_pair_name"); + } else { + MEMCPY(buf, str.ptr(), str.length() - 1); + comb_name.assign(buf, str.length() - 1); + } + } + return ret; +} + +int ObTransposeResolver::get_combine_name(ObIArray &exprs, ObString &comb_name) { + int ret = OB_SUCCESS; + ObIAllocator *allocator = NULL; + ObSqlString str; + char name_buf[OB_MAX_COLUMN_NAME_LENGTH]; + int64_t pos = 0; + if (OB_ISNULL(cur_resolver_) || + OB_ISNULL(allocator = cur_resolver_->params_.allocator_) || + OB_UNLIKELY(exprs.count() == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid argument", K(ret)); + } + for (int64_t j = 0; OB_SUCC(ret) && j < exprs.count(); ++j) { + ObRawExpr *expr = exprs.at(j); + pos = 0; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(expr->get_name(name_buf, OB_MAX_COLUMN_NAME_LENGTH, pos))) { + LOG_WARN("failed to get expr name", K(ret)); + } else if (pos == 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr name is empty", K(ret)); + } else if (OB_FAIL(str.append_fmt("%.*s_", int(pos), name_buf))) { + LOG_WARN("failed to append fmt", K(ret)); + } + } + if (OB_SUCC(ret)) { + char *buf = NULL; + if (OB_ISNULL(buf = static_cast(allocator->alloc(str.length() - 1)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("no more memory to create in_pair_name"); + } else { + MEMCPY(buf, str.ptr(), str.length() - 1); + comb_name.assign(buf, str.length() - 1); + } + } + return ret; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/resolver/dml/ob_transpose_resolver.h b/src/sql/resolver/dml/ob_transpose_resolver.h new file mode 100644 index 0000000000..2a6cac885d --- /dev/null +++ b/src/sql/resolver/dml/ob_transpose_resolver.h @@ -0,0 +1,220 @@ +/** + * 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. + */ + +#ifndef OCEANBASE_SRC_SQL_RESOLVER_DML_OB_TRANSPOSE_RESOLVER_H_ +#define OCEANBASE_SRC_SQL_RESOLVER_DML_OB_TRANSPOSE_RESOLVER_H_ +#include "sql/resolver/expr/ob_raw_expr.h" +#include "sql/resolver/dml/ob_dml_stmt.h" + +namespace oceanbase +{ +namespace sql +{ +class ObDMLResolver; +class TransposeDef; + +struct TransposeDef +{ + TransposeDef() : orig_table_item_(NULL), alias_name_() {} + void reset() + { + orig_table_item_ = NULL; + alias_name_.reset(); + } + inline virtual bool is_pivot() const = 0; + inline virtual bool is_unpivot() const = 0; + inline virtual bool need_use_unpivot_op() const { return false; } + virtual int assign(const TransposeDef &other); + int deep_copy(ObIRawExprCopier &expr_copier, const TransposeDef &other); + TO_STRING_KV(KPC_(orig_table_item), K_(alias_name)); + TableItem *orig_table_item_; + ObString alias_name_; +}; + +struct PivotDef : TransposeDef +{ + struct AggrPair + { + ObRawExpr *expr_; + ObString alias_name_; + AggrPair() : expr_(NULL), alias_name_() {} + ~AggrPair() {} + int assign(const AggrPair &other); + TO_STRING_KV(KPC_(expr), K_(alias_name)); + }; + + struct InPair + { + common::ObSEArray const_exprs_; + ObString name_; + InPair() : name_() {} + ~InPair() {} + int assign(const InPair &other); + TO_STRING_KV(K_(const_exprs), K_(name)); + }; + + PivotDef () {} + void reset() + { + TransposeDef::reset(); + group_columns_.reset(); + group_column_names_.reset(); + for_columns_.reset(); + for_column_names_.reset(); + aggr_pairs_.reset(); + in_pairs_.reset(); + } + inline bool is_pivot() const { return true; } + inline bool is_unpivot() const { return false; } + int assign(const PivotDef &other); + INHERIT_TO_STRING_KV("BasicDef", TransposeDef, "type", "PIVOT", + K_(aggr_pairs), K_(group_columns), K_(for_columns), K_(in_pairs), K_(alias_name)); + + // group columns of pivot / old columns of unpivot + common::ObSEArray group_columns_; + common::ObSEArray group_column_names_; + common::ObSEArray for_columns_; + common::ObSEArray for_column_names_; + common::ObSEArray aggr_pairs_; + common::ObSEArray in_pairs_; +}; + +struct UnpivotDef : TransposeDef +{ + struct InPair + { + common::ObSEArray const_exprs_; + common::ObSEArray column_names_; + common::ObSEArray column_exprs_; + InPair() {} + ~InPair() {} + int assign(const InPair &other); + TO_STRING_KV(K_(const_exprs), K_(column_names), K_(column_exprs)); + }; + + UnpivotDef() {} + void reset() + { + TransposeDef::reset(); + is_include_null_ = false; + orig_columns_.reset(); + orig_column_names_.reset(); + label_columns_.reset(); + value_columns_.reset(); + in_pairs_.reset(); + } + inline bool is_pivot() const { return false; } + inline bool is_unpivot() const { return true; } + inline bool is_include_null() const { return is_include_null_; } + inline bool is_exclude_null() const { return !is_include_null_; } + inline bool need_use_unpivot_op() const { return in_pairs_.count() > 1; } + void set_include_nulls(const bool is_include_nulls) { is_include_null_ = is_include_nulls; } + int assign(const UnpivotDef &other); + INHERIT_TO_STRING_KV("BasicDef", TransposeDef, "type", "UNPIVOT", + K_(is_include_null), K_(orig_columns), K_(orig_column_names), + K_(label_columns), K_(value_columns), K_(in_pairs)); + + bool is_include_null_; + common::ObSEArray orig_columns_; + common::ObSEArray orig_column_names_; + common::ObSEArray label_columns_; + common::ObSEArray value_columns_; + common::ObSEArray in_pairs_; +}; + +class ObTransposeResolver +{ +public: + ObTransposeResolver(ObDMLResolver *cur_resolver) + : cur_resolver_(cur_resolver) {} + virtual ~ObTransposeResolver() {} + + int resolve(const ParseNode &parse_tree); + + TableItem *get_table_item() { return table_item_; } + +private: + int resolve_transpose_clause(const ParseNode &transpose_node, + TableItem &orig_table_item, + TransposeDef *&trans_def, + common::ObIArray &columns_in_aggrs); + int resolve_pivot_clause(const ParseNode &transpose_node, + TableItem &orig_table_item, + PivotDef &pivot_def, + common::ObIArray &columns_in_aggrs); + int resolve_unpivot_clause(const ParseNode &transpose_node, + TableItem &orig_table_item, + UnpivotDef &unpivot_def); + int check_pivot_aggr_expr(ObRawExpr *expr) const; + int resolve_column_names(const ParseNode &column_node, + ObIArray &columns); + int resolve_columns(const ParseNode &column_node, + TableItem &table_item, + ObIArray &column_names, + ObIArray &columns); + int resolve_const_exprs(const ParseNode &expr_node, + ObIArray &const_exprs); + int resolve_table_column_item(const TableItem &table_item, + ObString &column_name, + ColumnItem *&column_item); + int resolve_all_table_columns(const TableItem &table_item, + ObIArray &column_items); + int get_old_or_group_column(const ObIArray &columns_in_aggrs, + TableItem &orig_table_item, + TransposeDef &trans_def); + int try_add_cast_to_unpivot(UnpivotDef &unpivot_def); + int get_merge_type_for_unpivot(ObIArray &left_types, + ObIArray &right_types, + ObIArray &res_types); + + int transform_to_view(TableItem &orig_table_item, + TransposeDef &trans_def, + TableItem *&view_table); + int get_exprs_for_pivot_table(PivotDef &pivot_def, + ObIArray &select_exprs, + ObIArray &group_exprs); + int build_select_expr_for_pivot(PivotDef::AggrPair &aggr_pair, + PivotDef::InPair &in_pair, + ObIArray &for_exprs, + ObRawExpr *&select_expr); + int get_exprs_for_unpivot_table(UnpivotDef &unpivot_def, + ObIArray &select_exprs, + ObIArray &condition_exprs); + int get_unpivot_item(UnpivotDef &unpivot_def, + ObIArray &select_exprs, + ObUnpivotItem *&unpivot_item); + int push_transpose_table_into_view(TableItem *&view_table, + TableItem *origin_table, + TransposeDef &trans_def, + ObIArray &select_exprs, + ObIArray &conditions, + ObIArray *group_exprs = NULL); + int add_new_table_item(TableItem *&new_table_item, const ObString &alias_name); + int generate_select_list(TableItem *table, ObIArray &basic_select_exprs); + + int get_column_item_idx_by_name(ObIArray &array, + const ObString &var, + int64_t &idx); + + int remove_column_item_by_names(ObIArray &column_items, + const ObIArray &names); + int get_combine_name(ObIArray &exprs, ObString &comb_name); + int get_combine_name(ObIArray &exprs, ObString &comb_name); + +private: + TableItem *table_item_; + ObDMLResolver *cur_resolver_; +}; + +} // namespace sql +} // namespace oceanbase +#endif /* OCEANBASE_SRC_SQL_RESOLVER_DML_OB_TRANSPOSE_RESOLVER_H_ */ diff --git a/src/sql/resolver/expr/ob_expr_info_flag.h b/src/sql/resolver/expr/ob_expr_info_flag.h index 1e00a9aa24..592ba44882 100644 --- a/src/sql/resolver/expr/ob_expr_info_flag.h +++ b/src/sql/resolver/expr/ob_expr_info_flag.h @@ -60,6 +60,8 @@ enum ObExprInfoFlag IS_OP_PSEUDO_COLUMN, IS_ASSIGN_EXPR, IS_MATCH_EXPR, + IS_OBJ_ACCESS_EXPR, + IS_UNPIVOT_EXPR, IS_ASSOCIATED_FLAG_END, //add IS_xxx flag before me //IS_CONST_EXPR and CNT_CONST_EXPR are not in the flag of associated extraction IS_CONST_EXPR, // expression contains calculable expression @@ -106,6 +108,7 @@ enum ObExprInfoFlag CNT_ASSIGN_EXPR, CNT_MATCH_EXPR, CNT_OBJ_ACCESS_EXPR, + CNT_UNPIVOT_EXPR, CNT_ASSOCIATED_FLAG_END, //add CNT_xxx flag before me BE_USED, // expression has been applied @@ -185,6 +188,7 @@ inline const char* get_expr_info_flag_str(const ObExprInfoFlag flag) case IS_ASSIGN_EXPR: { ret = "IS_ASSIGN_EXPR"; break; } case IS_CONST_EXPR: { ret = "IS_CONST_EXPR"; break; } case IS_MATCH_EXPR: { ret = "IS_MATCH_EXPR"; break; } + case IS_UNPIVOT_EXPR: { ret = "IS_UNPIVOT_EXPR"; break; } case CNT_CONST_EXPR: { ret = "CNT_CONST_EXPR"; break; } case CNT_CONST: { ret = "CNT_CONST"; break; } case CNT_COLUMN: { ret = "CNT_COLUMN"; break; } @@ -222,6 +226,7 @@ inline const char* get_expr_info_flag_str(const ObExprInfoFlag flag) case CNT_DYNAMIC_PARAM: { ret = "CNT_DYNAMIC_PARAM"; break; } case CNT_ENUM_OR_SET: { ret = "CNT_ENUM_OR_SET"; break; } case CNT_MATCH_EXPR: { ret = "CNT_MATCH_EXPR"; break; } + case CNT_UNPIVOT_EXPR: { ret = "CNT_UNPIVOT_EXPR"; break; } case CNT_ASSIGN_EXPR: { ret = "CNT_ASSIGN_EXPR"; break; } case BE_USED: { ret = "BE_USED"; break; } case IS_SIMPLE_COND: { ret = "IS_SIMPLE_COND"; break; } diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index d7583323a7..b6d75d7859 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -209,12 +209,13 @@ ObRawExpr::~ObRawExpr() //ObUnaryRefExpr(即subquery ref)必须由SubPlanFilter产生 //PSEUDO_COLUMN一般是由CTE或者层次查询产生 //SYS_CONNECT_BY_PATH,CONNECT_BY_ROOT由cby nestloop join产生 +//UNPIVOT必须由Unpivot operator产生 bool ObRawExpr::has_generalized_column(bool ignore_column/* = false */) const { return (!ignore_column && has_flag(CNT_COLUMN)) || has_flag(CNT_AGG) || has_flag(CNT_SET_OP) || has_flag(CNT_SUB_QUERY) || has_flag(CNT_WINDOW_FUNC) || has_flag(CNT_ROWNUM) || has_flag(CNT_PSEUDO_COLUMN) || has_flag(CNT_SEQ_EXPR) || has_flag(CNT_SYS_CONNECT_BY_PATH) || has_flag(CNT_CONNECT_BY_ROOT) - || has_flag(CNT_OP_PSEUDO_COLUMN) || has_flag(CNT_MATCH_EXPR); + || has_flag(CNT_OP_PSEUDO_COLUMN) || has_flag(CNT_UNPIVOT_EXPR) || has_flag(CNT_MATCH_EXPR); } @@ -252,7 +253,10 @@ bool ObRawExpr::is_vectorize_result() const // coredump because evaluate flag not cleared which reset datum's pointers depends. bool is_const = is_const_expr(); - return not_pre_calc && !is_const; + bool is_unpivot_label_expr = is_unpivot_expr() + && static_cast (this)->is_label_expr(); + + return not_pre_calc && !is_const && !is_unpivot_label_expr; } int ObRawExpr::assign(const ObRawExpr &other) @@ -2238,7 +2242,6 @@ int ObColumnRefRawExpr::assign(const ObRawExpr &other) column_name_ = tmp.column_name_; column_flags_ = tmp.column_flags_; dependant_expr_ = tmp.dependant_expr_; - is_unpivot_mocked_column_ = tmp.is_unpivot_mocked_column_; is_hidden_ = tmp.is_hidden_; is_lob_column_ = tmp.is_lob_column_; is_joined_dup_column_ = tmp.is_joined_dup_column_; @@ -7530,6 +7533,16 @@ int ObRawExprFactory::create_raw_expr(ObRawExpr::ExprClass expr_class, } break; } + case ObRawExpr::EXPR_UNPIVOT: { + ObUnpivotRawExpr *dest_unpivot_expr = NULL; + if (OB_FAIL(create_raw_expr(expr_type, dest_unpivot_expr)) || + OB_ISNULL(dest_unpivot_expr)) { + LOG_WARN("failed to allocate raw expr", KPC(dest_unpivot_expr), K(ret)); + } else { + dest = dest_unpivot_expr; + } + break; + } case ObRawExpr::EXPR_INVALID_CLASS: { ret = OB_ERR_UNEXPECTED; LOG_WARN("does not implement expr type copy", K(ret), K(expr_type), K(expr_class)); @@ -7791,6 +7804,115 @@ int ObMatchFunRawExpr::replace_param_expr(int64_t index, ObRawExpr *expr) return ret; } +//////////////////////////////////////////////////////////////// + +void ObUnpivotRawExpr::reset() +{ + ObRawExpr::reset(); + clear_child(); +} + +int ObUnpivotRawExpr::assign(const ObRawExpr &other) +{ + int ret = OB_SUCCESS; + if (OB_LIKELY(this != &other)) { + if (OB_UNLIKELY(get_expr_class() != other.get_expr_class())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid input expr", K(ret), K(other.get_expr_type())); + } else { + const ObUnpivotRawExpr &tmp = static_cast(other); + if (OB_FAIL(exprs_.assign(tmp.exprs_))) { + LOG_WARN("failed to assign exprs", K(ret)); + } + } + } + return ret; +} + +int ObUnpivotRawExpr::replace_expr(const ObIArray &other_exprs, + const ObIArray &new_exprs) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObTransformUtils::replace_exprs(other_exprs, new_exprs, exprs_))) { + LOG_WARN("failed to replace expr", K(ret)); + } else { /*do nothing*/ } + return ret; +} + +void ObUnpivotRawExpr::clear_child() +{ + exprs_.reset(); +} + +void ObUnpivotRawExpr::inner_calc_hash() +{ + expr_hash_ = common::do_hash(get_expr_type(), expr_hash_); + expr_hash_ = common::do_hash(is_label_expr(), expr_hash_); +} + +bool ObUnpivotRawExpr::inner_same_as( + const ObRawExpr &expr, + ObExprEqualCheckContext *check_context) const +{ + bool bool_ret = false; + if (expr.get_expr_class() != ObRawExpr::EXPR_UNPIVOT || + this->get_param_count() != expr.get_param_count()) { + /* do nothing */ + } else if (static_cast(expr).is_label_expr() != is_label_expr()) { + /* do nothing */ + } else { + bool_ret = true; + for (int64_t i = 0; bool_ret && i < expr.get_param_count(); ++i) { + if (NULL == this->get_param_expr(i) || NULL == expr.get_param_expr(i) + || !(this->get_param_expr(i)->same_as(*expr.get_param_expr(i), check_context))) { + bool_ret = false; + } + } + } + return bool_ret; +} + +int ObUnpivotRawExpr::do_visit(ObRawExprVisitor &visitor) +{ + return visitor.visit(*this); +} + +int ObUnpivotRawExpr::get_name_internal(char *buf, const int64_t buf_len, int64_t &pos, + ExplainType type) const { + int ret = OB_SUCCESS; + if (OB_FAIL(BUF_PRINTF("UNPIVOT("))) { + LOG_WARN("fail to BUF_PRINTF", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < get_param_count() ; ++i) { + if (OB_ISNULL(get_param_expr(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param expr is NULL", K(i), K(ret)); + } else if (OB_FAIL(get_param_expr(i)->get_name(buf, buf_len, pos, type))) { + LOG_WARN("fail to get_name", K(i), K(ret)); + } else if (i < get_param_count() - 1) { + if (OB_FAIL(BUF_PRINTF(", "))) { + LOG_WARN("fail to BUF_PRINTF", K(ret)); + } + } else {} + } + if (OB_SUCCESS == ret && OB_FAIL(BUF_PRINTF(")"))) { + LOG_WARN("fail to BUF_PRINTF", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (EXPLAIN_EXTENDED == type) { + if (OB_FAIL(BUF_PRINTF("("))) { + LOG_WARN("fail to BUF_PRINTF", K(ret)); + } else if (OB_FAIL(BUF_PRINTF("%p", this))) { + LOG_WARN("fail to BUF_PRINTF", K(ret)); + } else if (OB_FAIL(BUF_PRINTF(")"))) { + LOG_WARN("fail to BUF_PRINTF", K(ret)); + } else {} + } + } + return ret; +} + int ObUDTConstructorRawExpr::get_schema_object_version(share::schema::ObSchemaObjVersion &obj_version) { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/expr/ob_raw_expr.h b/src/sql/resolver/expr/ob_raw_expr.h index d11adf622e..b976b42cba 100644 --- a/src/sql/resolver/expr/ob_raw_expr.h +++ b/src/sql/resolver/expr/ob_raw_expr.h @@ -1847,7 +1847,8 @@ public: return is_column_ref_expr() || is_query_ref_expr() || is_aggr_expr() || is_set_op_expr() || is_win_func_expr() || has_flag(IS_ROWNUM) || has_flag(IS_PSEUDO_COLUMN) || has_flag(IS_SEQ_EXPR) || has_flag(IS_SYS_CONNECT_BY_PATH) - || has_flag(IS_CONNECT_BY_ROOT) || has_flag(IS_OP_PSEUDO_COLUMN); + || has_flag(IS_CONNECT_BY_ROOT) || has_flag(IS_OP_PSEUDO_COLUMN) + || has_flag(IS_UNPIVOT_EXPR); } // The expr result is vectorized, the batch result is the same if not vectorized result e.g: @@ -2709,7 +2710,6 @@ public: dependant_expr_(NULL), is_lob_column_(false), is_joined_dup_column_(false), - is_unpivot_mocked_column_(false), is_hidden_(false), from_alias_table_(false), is_rowkey_column_(false), @@ -2737,7 +2737,6 @@ public: dependant_expr_(NULL), is_lob_column_(false), is_joined_dup_column_(false), - is_unpivot_mocked_column_(false), is_hidden_(false), from_alias_table_(false), is_rowkey_column_(false), @@ -2765,7 +2764,6 @@ public: dependant_expr_(NULL), is_lob_column_(false), is_joined_dup_column_(false), - is_unpivot_mocked_column_(false), is_hidden_(false), from_alias_table_(false), is_rowkey_column_(false), @@ -2873,8 +2871,6 @@ public: void set_strict_json_column(int8_t v) { is_strict_json_column_ = v; } bool is_joined_dup_column() const { return is_joined_dup_column_; } void set_joined_dup_column(bool is_joined_dup_column) { is_joined_dup_column_ = is_joined_dup_column; } - bool is_unpivot_mocked_column() const { return is_unpivot_mocked_column_; } - void set_unpivot_mocked_column(const bool value) { is_unpivot_mocked_column_ = value; } bool is_hidden_column() const { return is_hidden_; } void set_hidden_column(const bool value) { is_hidden_ = value; } bool is_from_alias_table() const { return from_alias_table_; } @@ -2911,7 +2907,6 @@ public: K_(enum_set_values), K_(is_lob_column), K_(is_joined_dup_column), - K_(is_unpivot_mocked_column), K_(is_hidden), K_(from_alias_table), K_(is_rowkey_column), @@ -2934,7 +2929,6 @@ private: ObRawExpr *dependant_expr_; //TODO: @yuming.wyc @ryan.ly bool is_lob_column_; //TODO @hanhui add lob column bool is_joined_dup_column_; //is duplicated column in join (not in using). e.g., t1 (c1, c2) cross join t2 (c2,c3), c2 in t1 and t2 are joined_dup_column_ - bool is_unpivot_mocked_column_; //used for unpivot bool is_hidden_; //used for print hidden column bool from_alias_table_; bool is_rowkey_column_; @@ -5014,6 +5008,122 @@ private: ObRawExpr *search_key_; // user defined search query }; +class ObUnpivotRawExpr : public ObRawExpr +{ +public: + ObUnpivotRawExpr() + : ObRawExpr(), is_label_expr_(false) + { + set_expr_class(ObIRawExpr::EXPR_UNPIVOT); + } + + ObUnpivotRawExpr(common::ObIAllocator &alloc) + : ObRawExpr(alloc), is_label_expr_(false) + { + set_expr_class(ObIRawExpr::EXPR_UNPIVOT); + } + virtual ~ObUnpivotRawExpr() {} + int assign(const ObRawExpr &other) override; + virtual int replace_expr(const common::ObIArray &other_exprs, + const common::ObIArray &new_exprs) override; + + virtual void clear_child() override; + int add_param_expr(ObRawExpr *expr); + int remove_param_expr(int64_t index); + int replace_param_expr(int64_t index, ObRawExpr *expr); + virtual int64_t get_param_count() const override; + virtual const ObRawExpr *get_param_expr(int64_t index) const override; + virtual ObRawExpr *&get_param_expr(int64_t index) override; + virtual void reset(); + virtual void inner_calc_hash() override; + virtual bool inner_same_as(const ObRawExpr &expr, + ObExprEqualCheckContext *check_context = NULL) const override; + + virtual int do_visit(ObRawExprVisitor &visitor) override; + + virtual uint64_t hash_internal(uint64_t seed) const; + + int get_name_internal(char *buf, const int64_t buf_len, int64_t &pos, ExplainType type) const; + inline bool is_label_expr() const { return is_label_expr_; } + inline void set_label_expr(bool is_label_expr) { is_label_expr_ = is_label_expr; } + + VIRTUAL_TO_STRING_KV_CHECK_STACK_OVERFLOW(N_ITEM_TYPE, type_, + N_RESULT_TYPE, result_type_, + N_EXPR_INFO, info_, + K_(enum_set_values), + N_CHILDREN, exprs_, + K_(is_label_expr)); + +protected: + common::ObSEArray exprs_; + bool is_label_expr_; +private: + DISALLOW_COPY_AND_ASSIGN(ObUnpivotRawExpr); +}; + +inline const ObRawExpr *ObUnpivotRawExpr::get_param_expr(int64_t index) const +{ + const ObRawExpr *expr = NULL; + if (index >= 0 && index < exprs_.count()) { + expr = exprs_.at(index); + } + return expr; +} + +//here must return in two branch, because ret value is a *& +inline ObRawExpr *&ObUnpivotRawExpr::get_param_expr(int64_t index) +{ + if (index >= 0 && index < exprs_.count()) { + return exprs_.at(index); + } else { + return USELESS_POINTER; + } +} + +inline int ObUnpivotRawExpr::add_param_expr(ObRawExpr *expr) +{ + return exprs_.push_back(expr); +} + +inline int ObUnpivotRawExpr::remove_param_expr(int64_t index) +{ + int ret = common::OB_SUCCESS; + if (index < 0 || index >= exprs_.count()) { + ret = common::OB_INVALID_ARGUMENT; + } else { + ret = exprs_.remove(index); + } + return ret; +} + +inline int ObUnpivotRawExpr::replace_param_expr(int64_t index, ObRawExpr *expr) +{ + int ret = common::OB_SUCCESS; + if (index < 0 || index >= exprs_.count()) { + ret = common::OB_INVALID_ARGUMENT; + } else { + ObRawExpr *&target_expr = exprs_.at(index); + target_expr = expr; + } + return ret; +} + +inline int64_t ObUnpivotRawExpr::get_param_count() const +{ + return exprs_.count(); +} + +inline uint64_t ObUnpivotRawExpr::hash_internal(uint64_t seed) const +{ + uint64_t hash_value = seed; + for (int64_t i = 0; i < exprs_.count(); ++i) { + if (NULL != exprs_.at(i)) { + hash_value = common::do_hash(*(exprs_.at(i)), hash_value); + } + } + return hash_value; +} + /// visitor interface class ObRawExprVisitor { @@ -5051,6 +5161,7 @@ public: virtual int visit(ObWinFunRawExpr &expr) { UNUSED(expr); return common::OB_SUCCESS; } virtual int visit(ObPseudoColumnRawExpr &expr) { UNUSED(expr); return common::OB_SUCCESS; } virtual int visit(ObMatchFunRawExpr &expr) { UNUSED(expr); return common::OB_SUCCESS; } + virtual int visit(ObUnpivotRawExpr &expr) = 0; virtual bool skip_child(ObRawExpr &expr) { UNUSED(expr); return false; } private: // disallow copy diff --git a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp index d9160651a9..0a0c998ca0 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp @@ -3277,6 +3277,19 @@ int ObRawExprDeduceType::visit(ObMatchFunRawExpr &expr) return ret; } +int ObRawExprDeduceType::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(expr.get_param_count() <= 0) || + OB_ISNULL(expr.get_param_expr(0))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected expr", K(expr)); + } else { + expr.set_result_type(expr.get_param_expr(0)->get_result_type()); + } + return ret; +} + int ObRawExprDeduceType::init_normal_udf_expr(ObNonTerminalRawExpr &expr, ObExprOperator *op) { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/expr/ob_raw_expr_deduce_type.h b/src/sql/resolver/expr/ob_raw_expr_deduce_type.h index 6e067c77f2..8c2623d748 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.h +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.h @@ -66,6 +66,7 @@ public: virtual int visit(ObUDFRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); int add_implicit_cast(ObOpRawExpr &parent, const ObCastMode &cast_mode); int add_implicit_cast(ObCaseOpRawExpr &parent, const ObCastMode &cast_mode); diff --git a/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp b/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp index 9c2813a7d4..12a6be3bb7 100644 --- a/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp @@ -745,5 +745,21 @@ int ObRawExprInfoExtractor::add_deterministic(ObRawExpr &expr) return ret; } +int ObRawExprInfoExtractor::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(clear_info(expr))) { + LOG_WARN("failed to clear info", K(ret)); + } else if (OB_FAIL(pull_info(expr))) { + LOG_WARN("pull match against info failed", K(ret)); + } else if (OB_FAIL(expr.add_flag(IS_UNPIVOT_EXPR))) { + LOG_WARN("add flag failed", K(ret)); + } else if (OB_FAIL(expr.add_flag(CNT_UNPIVOT_EXPR))) { + LOG_WARN("add flag failed", K(ret)); + } + return ret; +} + + } // namespace sql } // namespace oceanbase diff --git a/src/sql/resolver/expr/ob_raw_expr_info_extractor.h b/src/sql/resolver/expr/ob_raw_expr_info_extractor.h index afc3365954..a554bef6a2 100644 --- a/src/sql/resolver/expr/ob_raw_expr_info_extractor.h +++ b/src/sql/resolver/expr/ob_raw_expr_info_extractor.h @@ -43,6 +43,7 @@ ObRawExprInfoExtractor() virtual int visit(ObPseudoColumnRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); private: // types and constants private: diff --git a/src/sql/resolver/expr/ob_raw_expr_modify_column_name.cpp b/src/sql/resolver/expr/ob_raw_expr_modify_column_name.cpp index c839a9e4ff..c652f95d73 100644 --- a/src/sql/resolver/expr/ob_raw_expr_modify_column_name.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_modify_column_name.cpp @@ -86,6 +86,12 @@ int ObRawExprModifyColumnName::visit(ObMatchFunRawExpr &expr) return common::OB_SUCCESS; } +int ObRawExprModifyColumnName::visit(ObUnpivotRawExpr &expr) +{ + UNUSED (expr); + return common::OB_SUCCESS; +} + int ObRawExprModifyColumnName::visit(ObSysFunRawExpr &expr) { UNUSED (expr); return common::OB_SUCCESS; diff --git a/src/sql/resolver/expr/ob_raw_expr_modify_column_name.h b/src/sql/resolver/expr/ob_raw_expr_modify_column_name.h index 7dac72885c..8f8f118525 100644 --- a/src/sql/resolver/expr/ob_raw_expr_modify_column_name.h +++ b/src/sql/resolver/expr/ob_raw_expr_modify_column_name.h @@ -54,6 +54,7 @@ public: virtual int visit(ObPseudoColumnRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); private: DISALLOW_COPY_AND_ASSIGN(ObRawExprModifyColumnName); diff --git a/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.cpp b/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.cpp index 87cafbde7e..291b182813 100644 --- a/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.cpp @@ -234,6 +234,13 @@ int ObRawExprPartExprChecker::visit(ObMatchFunRawExpr &expr) return ret; } +int ObRawExprPartExprChecker::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_ERR_UNEXPECTED; + UNUSED(expr); + return ret; +} + int ObRawExprPartExprChecker::visit(ObSysFunRawExpr &expr) { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.h b/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.h index fde1573f69..cc9f2e7d32 100644 --- a/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.h +++ b/src/sql/resolver/expr/ob_raw_expr_part_expr_checker.h @@ -43,6 +43,7 @@ public: virtual int visit(ObAliasRefRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); private: // types and constants const ObPartitionFuncType func_type_; diff --git a/src/sql/resolver/expr/ob_raw_expr_part_func_checker.cpp b/src/sql/resolver/expr/ob_raw_expr_part_func_checker.cpp index 7c790f3f53..753decb9ba 100644 --- a/src/sql/resolver/expr/ob_raw_expr_part_func_checker.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_part_func_checker.cpp @@ -151,6 +151,14 @@ int ObRawExprPartFuncChecker::visit(ObMatchFunRawExpr &expr) return ret; } +int ObRawExprPartFuncChecker::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_ERR_PARTITION_FUNCTION_IS_NOT_ALLOWED; + LOG_WARN("invalid partition function", K(ret), + "item_type", expr.get_expr_type()); + return ret; +} + int ObRawExprPartFuncChecker::visit(ObSysFunRawExpr &expr) { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/expr/ob_raw_expr_part_func_checker.h b/src/sql/resolver/expr/ob_raw_expr_part_func_checker.h index 2f050e4d4c..819a65f201 100644 --- a/src/sql/resolver/expr/ob_raw_expr_part_func_checker.h +++ b/src/sql/resolver/expr/ob_raw_expr_part_func_checker.h @@ -41,6 +41,7 @@ public: virtual int visit(ObAliasRefRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); private: // types and constants bool gen_col_check_; diff --git a/src/sql/resolver/expr/ob_raw_expr_print_visitor.cpp b/src/sql/resolver/expr/ob_raw_expr_print_visitor.cpp index 52f4e07dc6..7bdf33589e 100644 --- a/src/sql/resolver/expr/ob_raw_expr_print_visitor.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_print_visitor.cpp @@ -189,5 +189,15 @@ int ObRawExprPrintVisitor::visit(ObMatchFunRawExpr &expr) return ret; } +int ObRawExprPrintVisitor::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(databuff_printf(buf_, buf_len_, pos_, "%s<%ld>|", get_type_name(expr.get_expr_type()), + expr.get_param_count()))) { + LOG_WARN("databuff setop failed", K(ret)); + } + return ret; +} + } // namespace sql } // namespace oceanbase diff --git a/src/sql/resolver/expr/ob_raw_expr_print_visitor.h b/src/sql/resolver/expr/ob_raw_expr_print_visitor.h index 3fe8adc513..bd6d889f6d 100644 --- a/src/sql/resolver/expr/ob_raw_expr_print_visitor.h +++ b/src/sql/resolver/expr/ob_raw_expr_print_visitor.h @@ -37,6 +37,7 @@ public: virtual int visit(ObSetOpRawExpr &expr); virtual int visit(ObPlQueryRefRawExpr &expr); virtual int visit(ObMatchFunRawExpr &expr); + virtual int visit(ObUnpivotRawExpr &expr); int64_t to_string(char* buf, const int64_t buf_len) const; private: // types and constants diff --git a/src/sql/resolver/expr/ob_raw_expr_replacer.cpp b/src/sql/resolver/expr/ob_raw_expr_replacer.cpp index e951c0da41..f3fe879608 100644 --- a/src/sql/resolver/expr/ob_raw_expr_replacer.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_replacer.cpp @@ -281,6 +281,28 @@ int ObRawExprReplacer::visit(ObMatchFunRawExpr &expr) return ret; } +int ObRawExprReplacer::visit(ObUnpivotRawExpr &expr) +{ + int ret = OB_SUCCESS; + bool skip_expr = false; + if (OB_FAIL(check_skip_expr(expr, skip_expr))) { + LOG_WARN("failed to check skip expr"); + } else if (!skip_expr) { + ObRawExpr *new_expr = NULL; + bool need_replace = false; + int64_t count = expr.get_param_count(); + for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { + if (OB_FAIL(check_need_replace(expr.get_param_expr(i), new_expr, need_replace))) { + LOG_WARN("failed to check need replace", K(ret)); + } else if (need_replace) { + expr.get_param_expr(i) = new_expr; + replace_happened_ = true; + } + } + } + return ret; +} + int ObRawExprReplacer::visit(ObSysFunRawExpr &expr) { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/expr/ob_raw_expr_replacer.h b/src/sql/resolver/expr/ob_raw_expr_replacer.h index 64f707b7f9..035d4ed6c3 100644 --- a/src/sql/resolver/expr/ob_raw_expr_replacer.h +++ b/src/sql/resolver/expr/ob_raw_expr_replacer.h @@ -53,6 +53,7 @@ public: virtual int visit(ObAliasRefRawExpr &expr) override; virtual int visit(ObPseudoColumnRawExpr &expr) override; virtual int visit(ObMatchFunRawExpr &expr) override; + virtual int visit(ObUnpivotRawExpr &expr) override; virtual bool skip_child(ObRawExpr &expr) override; bool get_replace_happened() const { return replace_happened_; } diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index b3e08aeaba..09e4c5233f 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -10121,5 +10121,33 @@ int ObRawExprUtils::need_extra_cast_for_enumset(const ObExprResType &src_type, return ret; } +int ObRawExprUtils::build_unpivot_expr(ObRawExprFactory &expr_factory, + ObIArray ¶m_exprs, + ObRawExpr *&expr, + bool is_label_expr) +{ + int ret = OB_SUCCESS; + ObUnpivotRawExpr *unpivot_expr = NULL; + if (OB_FAIL(expr_factory.create_raw_expr(T_FUN_UNPIVOT, unpivot_expr))) { + LOG_WARN("failed to create raw expr", K(ret)); + } else if (OB_ISNULL(unpivot_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unpivot_expr is null", K(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < param_exprs.count(); ++i) { + ObRawExpr *param_expr = param_exprs.at(i); + if (OB_ISNULL(param_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param_expr is null", K(ret)); + } else if (OB_FAIL(unpivot_expr->add_param_expr(param_expr))) { + LOG_WARN("failed to add param expr", K(ret)); + } + } + if (OB_SUCC(ret)) { + unpivot_expr->set_label_expr(is_label_expr); + expr = unpivot_expr; + } + return ret; +} } } diff --git a/src/sql/resolver/expr/ob_raw_expr_util.h b/src/sql/resolver/expr/ob_raw_expr_util.h index 4be3fa075b..37f8babf14 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.h +++ b/src/sql/resolver/expr/ob_raw_expr_util.h @@ -1321,6 +1321,11 @@ public: ObIArray &new_exprs, ObRawExprCopier *copier, ObSQLSessionInfo *session_info); + + static int build_unpivot_expr(ObRawExprFactory &expr_factory, + ObIArray ¶m_exprs, + ObRawExpr *&unpivot_expr, + bool is_label_expr); private: static int need_extra_cast_for_enumset(const ObExprResType &src_type, const ObExprResType &dst_type, diff --git a/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.cpp b/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.cpp index af20f876ef..4acda48673 100644 --- a/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.cpp @@ -835,6 +835,12 @@ int ObRawExprWrapEnumSet::visit(ObMatchFunRawExpr &expr) return OB_SUCCESS; } +int ObRawExprWrapEnumSet::visit(ObUnpivotRawExpr &expr) +{ + UNUSED(expr); + return OB_SUCCESS; +} + bool ObRawExprWrapEnumSet::can_wrap_type_to_str(const ObRawExpr &expr) const { bool bret = false; diff --git a/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.h b/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.h index ccdb2d777b..1527f99243 100644 --- a/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.h +++ b/src/sql/resolver/expr/ob_raw_expr_wrap_enum_set.h @@ -52,6 +52,7 @@ public: int visit(ObPseudoColumnRawExpr &expr); int visit(ObPlQueryRefRawExpr &expr); int visit(ObMatchFunRawExpr &expr); + int visit(ObUnpivotRawExpr &expr); bool skip_child(); private: int visit_left_expr(ObOpRawExpr &expr, int64_t row_dimension, diff --git a/src/sql/resolver/mv/ob_mv_checker.cpp b/src/sql/resolver/mv/ob_mv_checker.cpp index c31579a642..3b6ed4766d 100644 --- a/src/sql/resolver/mv/ob_mv_checker.cpp +++ b/src/sql/resolver/mv/ob_mv_checker.cpp @@ -240,8 +240,8 @@ const char *ObMVChecker::get_table_type_str(const TableItem::TableType type) case TableItem::FUNCTION_TABLE: type_str = "FUNCTION_TABLE"; break; - case TableItem::UNPIVOT_TABLE: - type_str = "UNPIVOT_TABLE"; + case TableItem::TRANSPOSE_TABLE: + type_str = "TRANSPOSE_TABLE"; break; case TableItem::TEMP_TABLE: type_str = "TEMP_TABLE"; diff --git a/src/sql/rewrite/ob_transform_const_propagate.cpp b/src/sql/rewrite/ob_transform_const_propagate.cpp index 66318a79b0..5c37ce450c 100644 --- a/src/sql/rewrite/ob_transform_const_propagate.cpp +++ b/src/sql/rewrite/ob_transform_const_propagate.cpp @@ -2038,7 +2038,7 @@ int ObTransformConstPropagate::replace_check_constraint_exprs(ObDMLStmt *stmt, } else { LOG_TRACE("begin replace check constraint exprs", K(const_ctx), K(stmt->get_check_constraint_items())); for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_check_constraint_items().count(); ++i) { - ObDMLStmt::CheckConstraintItem &item = stmt->get_check_constraint_items().at(i); + CheckConstraintItem &item = stmt->get_check_constraint_items().at(i); for (int64_t j = 0; OB_SUCC(ret) && j < item.check_constraint_exprs_.count(); ++j) { ObRawExpr *check_constraint_expr = item.check_constraint_exprs_.at(j); bool is_valid = false; @@ -2050,8 +2050,8 @@ int ObTransformConstPropagate::replace_check_constraint_exprs(ObDMLStmt *stmt, OB_UNLIKELY(item.check_constraint_exprs_.count() != item.check_flags_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(item)); - } else if (!(item.check_flags_.at(j) & ObDMLStmt::CheckConstraintFlag::IS_VALIDATE_CHECK) && - !(item.check_flags_.at(j) & ObDMLStmt::CheckConstraintFlag::IS_RELY_CHECK)) { + } else if (!(item.check_flags_.at(j) & CheckConstraintFlag::IS_VALIDATE_CHECK) && + !(item.check_flags_.at(j) & CheckConstraintFlag::IS_RELY_CHECK)) { //do nothing } else if (OB_FAIL(check_constraint_expr_validity(check_constraint_expr, stmt->get_part_exprs(), @@ -2081,7 +2081,7 @@ int ObTransformConstPropagate::replace_check_constraint_exprs(ObDMLStmt *stmt, } int ObTransformConstPropagate::check_constraint_expr_validity(ObRawExpr *check_constraint_expr, - const ObIArray &part_items, + const ObIArray &part_items, ObIArray &expr_const_infos, ObRawExpr *&part_column_expr, ObIArray &old_column_exprs, @@ -2138,7 +2138,7 @@ int ObTransformConstPropagate::check_constraint_expr_validity(ObRawExpr *check_c int ObTransformConstPropagate::do_check_constraint_param_expr_vaildity( ObRawExpr *column_param_expr, ObRawExpr *non_column_param_expr, - const ObIArray &part_items, + const ObIArray &part_items, ObIArray &expr_const_infos, ObIArray &old_column_exprs, ObIArray &new_const_exprs, diff --git a/src/sql/rewrite/ob_transform_const_propagate.h b/src/sql/rewrite/ob_transform_const_propagate.h index 932db68424..3afcdfbd0c 100644 --- a/src/sql/rewrite/ob_transform_const_propagate.h +++ b/src/sql/rewrite/ob_transform_const_propagate.h @@ -305,7 +305,7 @@ private: bool &trans_happened); int check_constraint_expr_validity(ObRawExpr *check_constraint_expr, - const ObIArray &part_items, + const ObIArray &part_items, ObIArray &expr_const_infos, ObRawExpr *&part_column_expr, ObIArray &old_column_exprs, @@ -315,7 +315,7 @@ private: int do_check_constraint_param_expr_vaildity(ObRawExpr *column_param_expr, ObRawExpr *non_column_param_expr, - const ObIArray &part_items, + const ObIArray &part_items, ObIArray &expr_const_infos, ObIArray &old_column_exprs, ObIArray &new_const_exprs, diff --git a/src/sql/rewrite/ob_transform_groupby_pushdown.cpp b/src/sql/rewrite/ob_transform_groupby_pushdown.cpp index fc4cc8b291..175979479d 100644 --- a/src/sql/rewrite/ob_transform_groupby_pushdown.cpp +++ b/src/sql/rewrite/ob_transform_groupby_pushdown.cpp @@ -2239,7 +2239,7 @@ int ObTransformGroupByPushdown::push_down_group_by_into_view(ObSelectStmt *stmt, for (int64_t i = 0; OB_SUCC(ret) && i < table_index_array.count(); ++i) { int64_t idx = table_index_array.at(i); TableItem *table_item = NULL; - ObSEArray part_exprs; + ObSEArray part_exprs; FromItem from_item; if (idx <= 0 || idx > table_items.count()) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/rewrite/ob_transform_late_materialization.cpp b/src/sql/rewrite/ob_transform_late_materialization.cpp index 112280e12a..826be0eaf1 100644 --- a/src/sql/rewrite/ob_transform_late_materialization.cpp +++ b/src/sql/rewrite/ob_transform_late_materialization.cpp @@ -642,7 +642,7 @@ int ObTransformLateMaterialization::replace_expr_skip_part(ObSelectStmt &select_ int ret = OB_SUCCESS; ObStmtExprReplacer replacer; ObSEArray part_exprs; - const ObIArray &part_items = select_stmt.get_part_exprs(); + const ObIArray &part_items = select_stmt.get_part_exprs(); for (int64_t i = 0; OB_SUCC(ret) && i < part_items.count(); ++i) { if (part_items.at(i).part_expr_ != NULL && OB_FAIL(part_exprs.push_back(part_items.at(i).part_expr_))) { diff --git a/src/sql/rewrite/ob_transform_mv_rewrite.cpp b/src/sql/rewrite/ob_transform_mv_rewrite.cpp index c5e3a12e7a..ffbc971dfa 100644 --- a/src/sql/rewrite/ob_transform_mv_rewrite.cpp +++ b/src/sql/rewrite/ob_transform_mv_rewrite.cpp @@ -2743,7 +2743,7 @@ int ObTransformMVRewrite::create_mv_column_item(MvRewriteHelper &helper) } // 3.2. do fill part expr for query_stmt_ for (int64_t i = 0; OB_SUCC(ret) && i < mv_info.select_mv_stmt_->get_part_exprs().count(); ++i) { - ObDMLStmt::PartExprItem &part_item = mv_info.select_mv_stmt_->get_part_exprs().at(i); + PartExprItem &part_item = mv_info.select_mv_stmt_->get_part_exprs().at(i); ObRawExpr *part_expr = NULL; ObRawExpr *subpart_expr = NULL; if (OB_FAIL(part_expr_copier.copy_on_replace(part_item.part_expr_, part_expr))) { diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index 05e18c8ac8..5c9418adee 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -312,7 +312,7 @@ int ObTransformPreProcess::transform_one_stmt(common::ObIArray LOG_TRACE("succeed to transform for preserve order for fulltext search",K(is_happened), K(ret)); } } - if (OB_SUCC(ret) && OB_FAIL(reset_view_base_item(stmt))) { + if (OB_SUCC(ret) && OB_FAIL(reset_view_base_and_transpose_item(stmt))) { LOG_WARN("failed to reset view base item", K(ret)); } if (OB_SUCC(ret)) { @@ -2884,7 +2884,7 @@ int ObTransformPreProcess::pull_up_part_exprs(ObDMLStmt *stmt, LOG_WARN("failed to add replace pair", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < sel_stmt->get_part_exprs().count(); ++i) { - ObDMLStmt::PartExprItem pei = sel_stmt->get_part_exprs().at(i); + PartExprItem pei = sel_stmt->get_part_exprs().at(i); if (OB_FAIL(copier.copy_on_replace(pei.part_expr_, pei.part_expr_))) { LOG_WARN("failed to copy part expr", K(ret)); } else if (pei.subpart_expr_ != NULL @@ -5565,8 +5565,8 @@ int ObTransformPreProcess::transform_insert_only_merge_into(ObDMLStmt* stmt, ObD SemiInfo *semi_info = NULL; TableItem *view_table = NULL; TableItem *inner_target_table = NULL; - ObSEArray part_items; - ObSEArray inner_part_items; + ObSEArray part_items; + ObSEArray inner_part_items; ObSEArray column_items; ObSEArray inner_column_items; ObSEArray old_column_exprs; @@ -5657,7 +5657,7 @@ int ObTransformPreProcess::transform_insert_only_merge_into(ObDMLStmt* stmt, ObD LOG_WARN("failed to add column itemes", K(ret)); } else if (OB_FAIL(insert_stmt->get_part_expr_items(target_table->table_id_, part_items))) { LOG_WARN("failed to get part expr items", K(ret)); - } else if (OB_FAIL(deep_copy_stmt_objects(expr_copier, + } else if (OB_FAIL(deep_copy_stmt_objects(expr_copier, part_items, inner_part_items))) { LOG_WARN("failed to deep copy part expr items", K(ret)); @@ -11029,7 +11029,7 @@ int ObTransformPreProcess::construct_leaf_leading_table(ObDMLStmt *stmt, return ret; } -int ObTransformPreProcess::reset_view_base_item(ObDMLStmt *stmt) +int ObTransformPreProcess::reset_view_base_and_transpose_item(ObDMLStmt *stmt) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt)) { @@ -11044,6 +11044,7 @@ int ObTransformPreProcess::reset_view_base_item(ObDMLStmt *stmt) LOG_WARN("unexpected null", K(ret), KP(table_item)); } else { table_item->view_base_item_ = NULL; + table_item->transpose_table_def_ = NULL; } } } diff --git a/src/sql/rewrite/ob_transform_pre_process.h b/src/sql/rewrite/ob_transform_pre_process.h index 9205b4462d..ed0beab0b4 100644 --- a/src/sql/rewrite/ob_transform_pre_process.h +++ b/src/sql/rewrite/ob_transform_pre_process.h @@ -696,7 +696,7 @@ private: ObIArray &flattened_tables, ObLeadingTable &leading_table); int construct_leaf_leading_table(ObDMLStmt *stmt, TableItem *table, ObLeadingTable *&leading_table); - int reset_view_base_item(ObDMLStmt *stmt); + int reset_view_base_and_transpose_item(ObDMLStmt *stmt); private: DISALLOW_COPY_AND_ASSIGN(ObTransformPreProcess); diff --git a/src/sql/rewrite/ob_transform_predicate_move_around.cpp b/src/sql/rewrite/ob_transform_predicate_move_around.cpp index b16fa933c0..6a5635ca48 100644 --- a/src/sql/rewrite/ob_transform_predicate_move_around.cpp +++ b/src/sql/rewrite/ob_transform_predicate_move_around.cpp @@ -618,7 +618,7 @@ int ObTransformPredicateMoveAround::generate_basic_table_pullup_preds(ObDMLStmt LOG_WARN("get unexpected null", K(ret), K(stmt)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_check_constraint_items().count(); i++) { - ObDMLStmt::CheckConstraintItem &item = stmt->get_check_constraint_items().at(i); + CheckConstraintItem &item = stmt->get_check_constraint_items().at(i); bool on_null_side = false; if (OB_FAIL(ObOptimizerUtil::is_table_on_null_side( stmt, item.table_id_, on_null_side))) { @@ -636,8 +636,8 @@ int ObTransformPredicateMoveAround::generate_basic_table_pullup_preds(ObDMLStmt OB_UNLIKELY(item.check_constraint_exprs_.count() != item.check_flags_.count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(item)); - } else if (!(item.check_flags_.at(j) & ObDMLStmt::CheckConstraintFlag::IS_VALIDATE_CHECK) && - !(item.check_flags_.at(j) & ObDMLStmt::CheckConstraintFlag::IS_RELY_CHECK)) { + } else if (!(item.check_flags_.at(j) & CheckConstraintFlag::IS_VALIDATE_CHECK) && + !(item.check_flags_.at(j) & CheckConstraintFlag::IS_RELY_CHECK)) { //do nothing } else if (OB_FAIL(preds.push_back(check_constraint_expr))) { LOG_WARN("push back failed", K(ret)); diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index 4180719e9b..e5dac6c472 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -1369,10 +1369,10 @@ int ObTransformUtils::update_table_id_for_joined_table(const JoinedTable &other, return ret; } -int ObTransformUtils::update_table_id_for_part_item(const ObIArray &other_part_expr_items, +int ObTransformUtils::update_table_id_for_part_item(const ObIArray &other_part_expr_items, const uint64_t old_table_id, const uint64_t new_table_id, - ObIArray &part_expr_items) + ObIArray &part_expr_items) { int ret = OB_SUCCESS; if (OB_UNLIKELY(other_part_expr_items.count() != part_expr_items.count())) { @@ -1389,10 +1389,10 @@ int ObTransformUtils::update_table_id_for_part_item(const ObIArray &other_check_constraint_items, + const common::ObIArray &other_check_constraint_items, const uint64_t old_table_id, const uint64_t new_table_id, - common::ObIArray &check_constraint_items) + common::ObIArray &check_constraint_items) { int ret = OB_SUCCESS; if (OB_UNLIKELY(other_check_constraint_items.count() != check_constraint_items.count())) { @@ -7101,7 +7101,7 @@ int ObTransformUtils::adjust_updatable_view(ObRawExprFactory &expr_factory, ObIArray* origin_table_ids /* = NULL*/) { int ret = OB_SUCCESS; - ObSEArray part_exprs; + ObSEArray part_exprs; ObSelectStmt *view_stmt = NULL; ObRawExprCopier copier(expr_factory); ObSEArray select_list; @@ -7142,7 +7142,7 @@ int ObTransformUtils::adjust_updatable_view(ObRawExprFactory &expr_factory, LOG_WARN("failed to get part expr items", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < part_exprs.count(); ++i) { - ObDMLStmt::PartExprItem part_item; + PartExprItem part_item; if (OB_FAIL(part_item.deep_copy(copier, part_exprs.at(i)))) { LOG_WARN("failed to deep copy part expr item", K(ret)); } else { @@ -7262,7 +7262,7 @@ int ObTransformUtils::create_stmt_with_joined_table(ObTransformerCtx *ctx, ctx->src_hash_val_))) { LOG_WARN("failed to adjust statement id", K(ret)); } else { - ObSEArray part_items; + ObSEArray part_items; ObSEArray column_items; ObSqlBitSet<> from_tables_set; ObSEArray tmp_column_exprs; @@ -7347,7 +7347,7 @@ int ObTransformUtils::create_stmt_with_basic_table(ObTransformerCtx *ctx, ctx->src_hash_val_))) { LOG_WARN("failed to adjust statement id", K(ret)); } else { - ObSEArray part_items; + ObSEArray part_items; ObSEArray column_items; if (OB_FAIL(stmt->get_part_expr_items(table->table_id_, part_items))) { LOG_WARN("failed to get part expr items", K(ret)); @@ -7610,8 +7610,8 @@ int ObTransformUtils::create_inline_view(ObTransformerCtx *ctx, uint64_t table_id = basic_table_ids.at(i); TableItem *table = NULL; ObArray column_items; - ObArray part_expr_items; - ObDMLStmt::CheckConstraintItem check_constraint_item; + ObArray part_expr_items; + CheckConstraintItem check_constraint_item; if (OB_ISNULL(table = stmt->get_table_item_by_id(table_id))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table is null", K(ret), K(table)); diff --git a/src/sql/rewrite/ob_transform_utils.h b/src/sql/rewrite/ob_transform_utils.h index 6ec7a74b05..5acbc8d6d9 100644 --- a/src/sql/rewrite/ob_transform_utils.h +++ b/src/sql/rewrite/ob_transform_utils.h @@ -363,15 +363,15 @@ public: const uint64_t old_table_id, const uint64_t new_table_id, JoinedTable &joined_table); - static int update_table_id_for_part_item(const common::ObIArray &other_part_items, + static int update_table_id_for_part_item(const common::ObIArray &other_part_items, const uint64_t old_table_id, const uint64_t new_table_id, - common::ObIArray &part_items); + common::ObIArray &part_items); static int update_table_id_for_check_constraint_items( - const common::ObIArray &other_check_constraint_items, + const common::ObIArray &other_check_constraint_items, const uint64_t old_table_id, const uint64_t new_table_id, - common::ObIArray &check_constraint_items); + common::ObIArray &check_constraint_items); static int update_table_id_for_semi_info(const ObIArray &other_semi_infos, const uint64_t old_table_id, const uint64_t new_table_id, @@ -2070,10 +2070,12 @@ private: ObIArray &from_exprs, ObIArray &view_exprs); +public: static int extract_shared_exprs(ObDMLStmt *parent, ObSelectStmt *view_stmt, ObIArray &common_exprs, const ObIArray *extra_view_exprs = NULL); +private: static int is_scalar_expr(ObRawExpr* expr, bool &is_scalar); static int check_is_bypass_string_expr(const ObRawExpr *expr, diff --git a/src/sql/rewrite/ob_transform_win_magic.cpp b/src/sql/rewrite/ob_transform_win_magic.cpp index 21a8d1a668..c85aa50ac2 100644 --- a/src/sql/rewrite/ob_transform_win_magic.cpp +++ b/src/sql/rewrite/ob_transform_win_magic.cpp @@ -1427,7 +1427,7 @@ int ObTransformWinMagic::adjust_view_for_trans(ObDMLStmt *main_stmt, // push down table for (int64_t i = 0; OB_SUCC(ret) && i < roll_up_stmt->get_table_size(); i++) { TableItem *table = NULL; - ObSEArray part_exprs; + ObSEArray part_exprs; if (OB_ISNULL(table = roll_up_stmt->get_table_item(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("table item is null", K(ret)); @@ -1963,7 +1963,7 @@ int ObTransformWinMagic::push_down_join(ObDMLStmt *main_stmt, int ret = OB_SUCCESS; ObSelectStmt *view_stmt = NULL; ObSEArray renamed_cond; - ObSEArray part_exprs; + ObSEArray part_exprs; ObSEArray view_select_list; ObSEArray view_column_list; ObSEArray query_refs; diff --git a/unittest/sql/resolver/expr/test_raw_expr_canonicalizer.result b/unittest/sql/resolver/expr/test_raw_expr_canonicalizer.result index ae97350fdc..dfd8146d18 100644 --- a/unittest/sql/resolver/expr/test_raw_expr_canonicalizer.result +++ b/unittest/sql/resolver/expr/test_raw_expr_canonicalizer.result @@ -273,7 +273,6 @@ not not a > b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -321,7 +320,6 @@ not not a > b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -398,7 +396,6 @@ not a > b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -446,7 +443,6 @@ not a > b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -523,7 +519,6 @@ not a = b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -571,7 +566,6 @@ not a = b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -648,7 +642,6 @@ not a < b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -696,7 +689,6 @@ not a < b ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -774,7 +766,6 @@ not a is true ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -912,7 +903,6 @@ not a between 1 and 100 ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -1020,7 +1010,6 @@ not a between 1 and 100 ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2090,7 +2079,6 @@ not(not(a)) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2231,7 +2219,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2337,7 +2324,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2414,7 +2400,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2520,7 +2505,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2597,7 +2581,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2703,7 +2686,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2780,7 +2762,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2857,7 +2838,6 @@ A or (A And B) or (A And C) ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, diff --git a/unittest/sql/resolver/expr/test_raw_expr_resolver.result b/unittest/sql/resolver/expr/test_raw_expr_resolver.result index ebf5a711c9..2ee7dcd81c 100644 --- a/unittest/sql/resolver/expr/test_raw_expr_resolver.result +++ b/unittest/sql/resolver/expr/test_raw_expr_resolver.result @@ -1275,7 +1275,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -1930,7 +1929,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2024,7 +2022,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2273,7 +2270,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2322,7 +2318,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2633,7 +2628,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2927,7 +2921,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -2976,7 +2969,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3054,7 +3046,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3103,7 +3094,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3187,7 +3177,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3300,7 +3289,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3411,7 +3399,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3460,7 +3447,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3543,7 +3529,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3809,7 +3794,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -3921,7 +3905,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -4131,7 +4114,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -4213,7 +4195,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -4417,7 +4398,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -4591,7 +4571,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -4826,7 +4805,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -5011,7 +4989,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -5480,7 +5457,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -5529,7 +5505,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -5673,7 +5648,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false, @@ -5722,7 +5696,6 @@ ], "is_lob_column":false, "is_joined_dup_column":false, - "is_unpivot_mocked_column":false, "is_hidden":false, "from_alias_table":false, "is_rowkey_column":false,