/** * 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. * This file contains implementation support for the json table abstraction. */ #define USING_LOG_PREFIX SQL_ENG #include "ob_json_table_op.h" #include "share/object/ob_obj_cast_util.h" #include "share/object/ob_obj_cast.h" #include "share/ob_json_access_utils.h" #include "common/sql_mode/ob_sql_mode_utils.h" #include "sql/ob_sql_utils.h" #include "sql/engine/expr/ob_datum_cast.h" #include "sql/session/ob_sql_session_info.h" #include "sql/engine/ob_physical_plan.h" #include "sql/engine/expr/ob_expr_json_func_helper.h" #include "sql/engine/expr/ob_expr_json_value.h" #include "sql/engine/expr/ob_expr_json_query.h" #include "sql/engine/expr/ob_expr_json_exists.h" #include "lib/xml/ob_binary_aggregate.h" #include "lib/xml/ob_xpath.h" namespace oceanbase { using namespace common; namespace sql { /* json value mismatch type { MISSING : 0, EXTRA : 1, TYPE : 2, EMPTY : 3} */ const static int32_t JSN_VALUE_TYPE_MISSING_DATA = 0; const static int32_t JSN_VALUE_TYPE_EXTRA_DATA = 1; const static int32_t JSN_VALUE_TYPE_TYPE_ERROR = 2; const static int32_t JSN_VALUE_TYPE_IMPLICIT = 3; /* json exists */ const static int32_t JSN_EXIST_FALSE = 0; const static int32_t JSN_EXIST_TRUE = 1; const static int32_t JSN_EXIST_ERROR = 2; const static int32_t JSN_EXIST_DEFAULT = 3; #define SET_COVER_ERROR(jt_ctx_ptr, error_code) \ {\ if (!(jt_ctx_ptr)->is_cover_error_) { \ (jt_ctx_ptr)->is_cover_error_ = true; \ (jt_ctx_ptr)->error_code_ = error_code; \ } \ } #define EVAL_COVER_CODE(jt_ctx_ptr, error_code) \ {\ if ((jt_ctx_ptr)->is_cover_error_) { \ error_code = (jt_ctx_ptr)->error_code_; \ } \ } #define RESET_COVER_CODE(jt_ctx_ptr) \ {\ if ((jt_ctx_ptr)->is_cover_error_) { \ (jt_ctx_ptr)->is_cover_error_ = false; \ (jt_ctx_ptr)->error_code_ = 0; \ } \ } ObJtColInfo::ObJtColInfo() : col_type_(0), truncate_(0), format_json_(0), wrapper_(0), allow_scalar_(0), output_column_idx_(-1), empty_expr_id_(-1), error_expr_id_(-1), col_name_(), path_(), on_empty_(3), on_error_(3), on_mismatch_(3), on_mismatch_type_(3), data_type_(), parent_id_(-1), id_(-1) {} ObJtColInfo::ObJtColInfo(const ObJtColInfo& info) : col_type_(info.col_type_), truncate_(info.truncate_), format_json_(info.format_json_), wrapper_(info.wrapper_), allow_scalar_(info.allow_scalar_), output_column_idx_(info.output_column_idx_), empty_expr_id_(info.empty_expr_id_), error_expr_id_(info.error_expr_id_), col_name_(info.col_name_), path_(info.path_), on_empty_(info.on_empty_), on_error_(info.on_error_), on_mismatch_(info.on_mismatch_), on_mismatch_type_(info.on_mismatch_type_), data_type_(info.data_type_), parent_id_(info.parent_id_), id_(info.id_) {} int ObJtColInfo::deep_copy(const ObJtColInfo& src, ObIAllocator* allocator) { int ret = OB_SUCCESS; if (src.col_name_.length() > 0) { void *name_buf = allocator->alloc(src.col_name_.length()); if (OB_ISNULL(name_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(name_buf, src.col_name_.ptr(), src.col_name_.length()); col_name_.assign(static_cast(name_buf), src.col_name_.length()); } } if (OB_SUCC(ret) && src.path_.length() > 0) { void *path_buf = allocator->alloc(src.path_.length()); if (OB_ISNULL(path_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { MEMCPY(path_buf, src.path_.ptr(), src.path_.length()); path_.assign(static_cast(path_buf), src.path_.length()); } } if (OB_SUCC(ret)) { col_type_ = src.col_type_; truncate_ = src.truncate_; format_json_ = src.format_json_; wrapper_ = src.wrapper_; allow_scalar_ = src.allow_scalar_; output_column_idx_ = src.output_column_idx_; empty_expr_id_ = src.empty_expr_id_; error_expr_id_ = src.error_expr_id_; on_empty_ = src.on_empty_; on_error_ = src.on_error_; on_mismatch_ = src.on_mismatch_; on_mismatch_type_ = src.on_mismatch_type_; data_type_ = src.data_type_; parent_id_ = src.parent_id_; id_ = src.id_; } return ret; } int ObJtColInfo::serialize(char *buf, int64_t buf_len, int64_t &pos) const { INIT_SUCC(ret); OB_UNIS_ENCODE(col_type_); OB_UNIS_ENCODE(truncate_); OB_UNIS_ENCODE(format_json_); OB_UNIS_ENCODE(wrapper_); OB_UNIS_ENCODE(allow_scalar_); OB_UNIS_ENCODE(output_column_idx_); OB_UNIS_ENCODE(empty_expr_id_); OB_UNIS_ENCODE(error_expr_id_); OB_UNIS_ENCODE(col_name_); OB_UNIS_ENCODE(path_); OB_UNIS_ENCODE(on_empty_); OB_UNIS_ENCODE(on_error_); OB_UNIS_ENCODE(on_mismatch_); OB_UNIS_ENCODE(on_mismatch_type_); OB_UNIS_ENCODE(data_type_); OB_UNIS_ENCODE(parent_id_); OB_UNIS_ENCODE(id_); return ret; } int ObJtColInfo::deserialize(const char *buf, const int64_t data_len, int64_t &pos) { INIT_SUCC(ret); OB_UNIS_DECODE(col_type_); OB_UNIS_DECODE(truncate_); OB_UNIS_DECODE(format_json_); OB_UNIS_DECODE(wrapper_); OB_UNIS_DECODE(allow_scalar_); OB_UNIS_DECODE(output_column_idx_); OB_UNIS_DECODE(empty_expr_id_); OB_UNIS_DECODE(error_expr_id_); OB_UNIS_DECODE(col_name_); OB_UNIS_DECODE(path_); OB_UNIS_DECODE(on_empty_); OB_UNIS_DECODE(on_error_); OB_UNIS_DECODE(on_mismatch_); OB_UNIS_DECODE(on_mismatch_type_); OB_UNIS_DECODE(data_type_); OB_UNIS_DECODE(parent_id_); OB_UNIS_DECODE(id_); return ret; } int64_t ObJtColInfo::get_serialize_size() const { int64_t len = 0; OB_UNIS_ADD_LEN(col_type_); OB_UNIS_ADD_LEN(truncate_); OB_UNIS_ADD_LEN(format_json_); OB_UNIS_ADD_LEN(wrapper_); OB_UNIS_ADD_LEN(allow_scalar_); OB_UNIS_ADD_LEN(output_column_idx_); OB_UNIS_ADD_LEN(empty_expr_id_); OB_UNIS_ADD_LEN(error_expr_id_); OB_UNIS_ADD_LEN(col_name_); OB_UNIS_ADD_LEN(path_); OB_UNIS_ADD_LEN(on_empty_); OB_UNIS_ADD_LEN(on_error_); OB_UNIS_ADD_LEN(on_mismatch_); OB_UNIS_ADD_LEN(on_mismatch_type_); OB_UNIS_ADD_LEN(data_type_); OB_UNIS_ADD_LEN(parent_id_); OB_UNIS_ADD_LEN(id_); return len; } int ObJtColInfo::from_JtColBaseInfo(const ObJtColBaseInfo& info) { INIT_SUCC(ret); col_type_ = info.col_type_; truncate_ = info.truncate_; format_json_ = info.format_json_; wrapper_ = info.wrapper_; allow_scalar_ = info.allow_scalar_; output_column_idx_ = info.output_column_idx_; empty_expr_id_ = info.empty_expr_id_; error_expr_id_ = info.error_expr_id_; col_name_ = info.col_name_; path_ = info.path_; on_empty_ = info.on_empty_; on_error_ = info.on_error_; on_mismatch_ = info.on_mismatch_; on_mismatch_type_ = info.on_mismatch_type_; data_type_ = info.data_type_; parent_id_ = info.parent_id_; id_ = info.id_; return ret; } static int construct_table_func_join_node(ObIAllocator* allocator, const ObJtColInfo& col_info, JoinNode*& jt_node) { INIT_SUCC(ret); void* node_buf = static_cast(jt_node); if (OB_ISNULL(node_buf)) { node_buf = allocator->alloc(sizeof(JoinNode)); if (OB_ISNULL(node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc col node buffer", K(ret)); } jt_node = static_cast(new(node_buf)JoinNode()); } else { jt_node = static_cast(new(node_buf)JoinNode()); } return ret; } static int construct_table_func_reg_node(ObIAllocator* allocator, const ObJtColInfo& col_info, ObRegCol*& jt_node) { INIT_SUCC(ret); void* node_buf = allocator->alloc(sizeof(ObRegCol)); if (OB_ISNULL(node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc col node buffer", K(ret)); } else { jt_node = static_cast(new(node_buf)ObRegCol(col_info)); } return ret; } static int construct_table_func_union_node(ObIAllocator* allocator, const ObJtColInfo& col_info, UnionNode*& jt_node) { INIT_SUCC(ret); void* node_buf = allocator->alloc(sizeof(UnionNode)); if (OB_ISNULL(node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc col node buffer", K(ret)); } else { jt_node = static_cast(new(node_buf)UnionNode()); } return ret; } static int construct_table_func_scan_node(ObIAllocator* allocator, const ObJtColInfo& col_info, ScanNode*& jt_node) { INIT_SUCC(ret); void* node_buf = allocator->alloc(sizeof(ScanNode)); if (OB_ISNULL(node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc col node buffer", K(ret)); } else { jt_node = static_cast(new(node_buf)ScanNode(col_info)); } return ret; } void JtColTreeNode::destroy() { regular_cols_.reset(); for (size_t i = 0; i < nested_cols_.count(); ++i) { JtColTreeNode* tmp_node = nested_cols_.at(i); tmp_node->destroy(); } nested_cols_.reset(); } OB_DEF_SERIALIZE(ObJsonTableSpec) { INIT_SUCC(ret); BASE_SER((ObJsonTableSpec, ObOpSpec)); OB_UNIS_ENCODE(value_expr_); OB_UNIS_ENCODE(column_exprs_); OB_UNIS_ENCODE(emp_default_exprs_); OB_UNIS_ENCODE(err_default_exprs_); OB_UNIS_ENCODE(has_correlated_expr_); int32_t column_count = cols_def_.count(); OB_UNIS_ENCODE(column_count); for (size_t i = 0; OB_SUCC(ret) && i < cols_def_.count(); ++i) { const ObJtColInfo& info = *cols_def_.at(i); OB_UNIS_ENCODE(info); } if (table_type_ == MulModeTableType::OB_ORA_XML_TABLE_TYPE) { OB_UNIS_ENCODE(table_type_); OB_UNIS_ENCODE(namespace_def_); } return ret; } OB_DEF_SERIALIZE_SIZE(ObJsonTableSpec) { int64_t len = 0; BASE_ADD_LEN((ObJsonTableSpec, ObOpSpec)); OB_UNIS_ADD_LEN(value_expr_); OB_UNIS_ADD_LEN(column_exprs_); OB_UNIS_ADD_LEN(emp_default_exprs_); OB_UNIS_ADD_LEN(err_default_exprs_); OB_UNIS_ADD_LEN(has_correlated_expr_); int32_t column_count = cols_def_.count(); OB_UNIS_ADD_LEN(column_count); for (size_t i = 0; i < cols_def_.count(); ++i) { const ObJtColInfo& info = *cols_def_.at(i); OB_UNIS_ADD_LEN(info); } if (table_type_ == MulModeTableType::OB_ORA_XML_TABLE_TYPE) { OB_UNIS_ADD_LEN(table_type_); OB_UNIS_ADD_LEN(namespace_def_); } return len; } OB_DEF_DESERIALIZE(ObJsonTableSpec) { INIT_SUCC(ret); BASE_DESER((ObJsonTableSpec, ObOpSpec)); OB_UNIS_DECODE(value_expr_); OB_UNIS_DECODE(column_exprs_); OB_UNIS_DECODE(emp_default_exprs_); OB_UNIS_DECODE(err_default_exprs_); OB_UNIS_DECODE(has_correlated_expr_); int32_t column_count = 0; int8_t table_type_flag = OB_JSON_TABLE; OB_UNIS_DECODE(column_count); if (OB_SUCC(ret) && OB_FAIL(cols_def_.init(column_count))) { LOG_WARN("fail to init cols def array.", K(ret), K(column_count)); } for (size_t i = 0; OB_SUCC(ret) && i < column_count; ++i) { void* col_info_buf = alloc_->alloc(sizeof(ObJtColInfo)); if (OB_ISNULL(col_info_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate col node buffer.", K(ret)); } else { ObJtColInfo* col_info = static_cast(new (col_info_buf) ObJtColInfo()); ObJtColInfo& tmp_col_info = *col_info; OB_UNIS_DECODE(tmp_col_info); *col_info = tmp_col_info; if (OB_FAIL(cols_def_.push_back(col_info))) { LOG_WARN("fail to store col info.", K(ret), K(cols_def_.count())); } else if (col_info->col_type_ >= COL_TYPE_VAL_EXTRACT_XML) { table_type_flag = OB_XML_TABLE; } } } if (table_type_flag == OB_XML_TABLE) { OB_UNIS_DECODE(table_type_); OB_UNIS_DECODE(namespace_def_); } return ret; } int ObJsonTableOp::generate_table_exec_tree(ObIAllocator* allocator, const JtColTreeNode& orig_col, JoinNode*& join_col) { INIT_SUCC(ret); int reg_count = orig_col.regular_cols_.count(); int nest_count = orig_col.nested_cols_.count(); ScanNode* scan_col = nullptr; if (OB_FAIL(construct_table_func_join_node(allocator, orig_col.col_base_info_, join_col))) { LOG_WARN("fail to construct join col node", K(ret)); } else if (OB_FAIL(construct_table_func_scan_node(allocator, orig_col.col_base_info_, scan_col))) { LOG_WARN("fail to construct scan col node", K(ret)); } else { join_col->set_left(scan_col); } for (int i = 0; OB_SUCC(ret) && i < reg_count; ++i) { ObRegCol* reg_node = nullptr; if (OB_FAIL(construct_table_func_reg_node(allocator, orig_col.regular_cols_.at(i)->col_base_info_, reg_node))) { LOG_WARN("fail to construct reg col node", K(ret), K(reg_count), K(i)); } else { if (OB_FAIL(scan_col->add_reg_column_node(reg_node))) { LOG_WARN("fail to store col node", K(ret), K(reg_count), K(i)); } } } if (OB_SUCC(ret) && nest_count > 0) { common::ObArray ji_nodes; for (size_t i = 0; OB_SUCC(ret) && i < nest_count; ++i) { UnionNode* ji_node = nullptr; if (OB_FAIL(construct_table_func_union_node(allocator, orig_col.nested_cols_.at(i)->col_base_info_, ji_node))) { LOG_WARN("fail to construct join col node", K(ret)); } else if (OB_FAIL(ji_nodes.push_back(ji_node))) { LOG_WARN("fail to store ji nodes in tmp array", K(ret), K(nest_count), K(i)); } } if (OB_SUCC(ret)) { int j = 0; UnionNode* last_node = nullptr; join_col->set_right(ji_nodes.at(j)); last_node = ji_nodes.at(j); ++j; while (j < nest_count) { // nested col/union node in right child UnionNode* cur_node = ji_nodes.at(j); last_node->set_right(cur_node); last_node = cur_node; ++j; }; for (int i = 0; OB_SUCC(ret) && i < nest_count; ++i) { JoinNode* col_node = nullptr; if (OB_FAIL(generate_table_exec_tree(allocator, *orig_col.nested_cols_.at(i), col_node))) { LOG_WARN("fail to generate sub col node", K(ret), K(i)); } else { ji_nodes.at(i)->set_left(col_node); } } } } return ret; } int ObJsonTableOp::generate_table_exec_tree() { INIT_SUCC(ret); if (OB_FAIL(generate_column_trees(def_root_))) { LOG_WARN("fail to generate column tree", K(ret)); } else if (OB_FAIL(generate_table_exec_tree(allocator_, *def_root_, root_))) { LOG_WARN("fail to generate sub col node", K(ret)); } return ret; } int ObJsonTableSpec::dup_origin_column_defs(ObIArray& columns) { INIT_SUCC(ret); for (size_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) { void* col_info_buf = alloc_->alloc(sizeof(ObJtColInfo)); if (OB_ISNULL(col_info_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate col node buffer.", K(ret)); } else { ObJtColInfo col_info; if (OB_FAIL(col_info.from_JtColBaseInfo(*columns.at(i)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to transform to jtcolinfo", K(ret)); } else { ObJtColInfo* col = static_cast(new (col_info_buf) ObJtColInfo()); if (OB_FAIL(col->deep_copy(col_info, alloc_))) { LOG_WARN("fail to deep copy col node", K(ret)); } else if (OB_FAIL(cols_def_.push_back(col))) { LOG_WARN("fail to store col node", K(cols_def_.count()), K(ret)); } } } } return ret; } int ObJsonTableOp::find_column(int32_t id, JtColTreeNode* root, JtColTreeNode*& col) { INIT_SUCC(ret); common::ObArray col_stack; if (OB_FAIL(col_stack.push_back(root))) { LOG_WARN("fail to store col node tmp", K(ret)); } bool exists = false; while (OB_SUCC(ret) && !exists && col_stack.count() > 0) { JtColTreeNode* cur_col = col_stack.at(col_stack.count() - 1); if (cur_col->col_base_info_.id_ == id) { exists = true; col = cur_col; } else if (cur_col->col_base_info_.parent_id_ < 0 || cur_col->col_base_info_.col_type_ == static_cast(NESTED_COL_TYPE)) { col_stack.remove(col_stack.count() - 1); for (size_t i = 0; !exists && i < cur_col->nested_cols_.count(); ++i) { JtColTreeNode* nest_col = cur_col->nested_cols_.at(i); if (nest_col->col_base_info_.id_ == id) { exists = true; col = nest_col; } else if (nest_col->col_base_info_.col_type_ == static_cast(NESTED_COL_TYPE) && OB_FAIL(col_stack.push_back(nest_col))) { LOG_WARN("fail to store col node tmp", K(ret)); } } } } if (OB_SUCC(ret) && !exists) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to find col node", K(ret)); } return ret; } int ObJsonTableOp::generate_column_trees(JtColTreeNode*& root) { INIT_SUCC(ret); const ObJsonTableSpec* spec_ptr = reinterpret_cast(&spec_); const ObIArray& plain_def = spec_ptr->cols_def_; for (size_t i = 0; OB_SUCC(ret) && i < plain_def.count(); ++i) { const ObJtColInfo& info = *plain_def.at(i); JtColTreeNode* col_def = static_cast(allocator_->alloc(sizeof(JtColTreeNode))); if (OB_ISNULL(col_def)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate col node", K(ret)); } else { col_def = new (col_def) JtColTreeNode(info); } if (OB_FAIL(ret)) { } else { JtColTreeNode* parent = nullptr; if (info.parent_id_ < 0) { root = col_def; } else if (OB_FAIL(find_column(info.parent_id_, root, parent))) { LOG_WARN("fail to find col node parent", K(ret), K(info.parent_id_)); } else if (info.col_type_ == static_cast(NESTED_COL_TYPE)) { if (OB_FAIL(parent->nested_cols_.push_back(col_def))) { LOG_WARN("fail to store col node", K(ret), K(parent->nested_cols_.count())); } } else if (OB_FAIL(parent->regular_cols_.push_back(col_def))) { LOG_WARN("fail to store col node", K(ret), K(parent->nested_cols_.count())); } } } return ret; } int ObJsonTableOp::inner_open() { INIT_SUCC(ret); if (OB_FAIL(init())) { LOG_WARN("failed to init.", K(ret)); } else if (OB_ISNULL(MY_SPEC.value_expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to open iter, value expr is null.", K(ret)); } else if (OB_FAIL(root_->open(&jt_ctx_))) { LOG_WARN("failed to open table func xml column node.", K(ret)); } else { is_evaled_ = false; } return ret; } int ObJsonTableOp::inner_rescan() { int ret = OB_SUCCESS; if (OB_FAIL(ObOperator::inner_rescan())) { LOG_WARN("failed to inner rescan", K(ret)); } else { jt_ctx_.row_alloc_.reuse(); } if (OB_FAIL(ret)) { } else if (OB_FAIL(reset_variable())) { LOG_WARN("failed to inner open", K(ret)); } return ret; } int ObJsonTableOp::reset_variable() { INIT_SUCC(ret); jt_ctx_.is_cover_error_ = false; jt_ctx_.error_code_ = 0; jt_ctx_.is_need_end_ = 0; if (OB_FAIL(ObXmlUtil::create_mulmode_tree_context(&jt_ctx_.row_alloc_, jt_ctx_.mem_ctx_))) { LOG_WARN("fail to create tree memory context", K(ret)); } if (OB_FAIL(ret)) { } else if (OB_ISNULL(MY_SPEC.value_expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to open iter, value expr is null.", K(ret)); } else if (OB_FAIL(root_->reset(&jt_ctx_))) { LOG_WARN("failed to open table func xml column node.", K(ret)); } else { is_evaled_ = false; } return ret; } int ObJsonTableOp::switch_iterator() { INIT_SUCC(ret); return OB_ITER_END; } int ObJsonTableOp::init() { INIT_SUCC(ret); if (!is_inited_) { const ObJsonTableSpec* spec_ptr = reinterpret_cast(&spec_); jt_ctx_.spec_ptr_ = const_cast(spec_ptr); if (OB_FAIL(generate_table_exec_tree())) { LOG_WARN("fail to init json table op, as generate exec tree occur error.", K(ret)); } else { const sql::ObSQLSessionInfo *session = get_exec_ctx().get_my_session(); uint64_t tenant_id = -1; if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { tenant_id = session->get_effective_tenant_id(); is_inited_ = true; jt_ctx_.spec_ptr_ = const_cast(spec_ptr); jt_ctx_.eval_ctx_ = &eval_ctx_; jt_ctx_.exec_ctx_ = &get_exec_ctx(); jt_ctx_.row_alloc_.set_tenant_id(tenant_id); jt_ctx_.op_exec_alloc_ = allocator_; jt_ctx_.is_evaled_ = false; jt_ctx_.is_charset_converted_ = false; jt_ctx_.res_obj_ = nullptr; jt_ctx_.jt_op_ = this; jt_ctx_.is_const_input_ = !MY_SPEC.has_correlated_expr_; } } void* table_func_buf = NULL; if (OB_FAIL(ret)) { } else if (jt_ctx_.is_json_table_func()) { table_func_buf = jt_ctx_.op_exec_alloc_->alloc(sizeof(JsonTableFunc)); if (OB_ISNULL(table_func_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate table func buf", K(ret)); } else if (OB_ISNULL(jt_ctx_.table_func_ = new (table_func_buf) JsonTableFunc())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to new json array node", K(ret)); } } else if (OB_FAIL(ObXmlUtil::create_mulmode_tree_context(jt_ctx_.op_exec_alloc_, jt_ctx_.xpath_ctx_))) { LOG_WARN("fail to create xpath memory context", K(ret)); } else if (jt_ctx_.is_xml_table_func()) { table_func_buf = jt_ctx_.op_exec_alloc_->alloc(sizeof(XmlTableFunc)); if (OB_ISNULL(table_func_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate table func buf", K(ret)); } else if (OB_ISNULL(jt_ctx_.table_func_ = new (table_func_buf) XmlTableFunc())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to new json array node", K(ret)); } } } jt_ctx_.is_cover_error_ = false; jt_ctx_.error_code_ = 0; jt_ctx_.is_need_end_ = 0; if (OB_SUCC(ret) && OB_FAIL(ObXmlUtil::create_mulmode_tree_context(&jt_ctx_.row_alloc_, jt_ctx_.mem_ctx_))) { LOG_WARN("fail to create tree memory context", K(ret)); } return ret; } int ObJsonTableOp::inner_close() { INIT_SUCC(ret); if (OB_NOT_NULL(root_)) { root_->destroy(); } if (OB_NOT_NULL(def_root_)) { def_root_->destroy(); } jt_ctx_.row_alloc_.clear(); if (OB_NOT_NULL(jt_ctx_.table_func_) && OB_NOT_NULL(jt_ctx_.op_exec_alloc_)) { jt_ctx_.op_exec_alloc_->free(jt_ctx_.table_func_); } if (OB_NOT_NULL(jt_ctx_.xpath_ctx_) && OB_NOT_NULL(jt_ctx_.op_exec_alloc_)) { jt_ctx_.op_exec_alloc_->free(jt_ctx_.xpath_ctx_); } return ret; } void ObJsonTableOp::reset_columns() { for (size_t i = 0; i < col_count_; ++i) { ObExpr* col_expr = jt_ctx_.spec_ptr_->column_exprs_.at(i); col_expr->locate_datum_for_write(*jt_ctx_.eval_ctx_).reset(); col_expr->locate_datum_for_write(*jt_ctx_.eval_ctx_).set_null(); col_expr->get_eval_info(*jt_ctx_.eval_ctx_).evaluated_ = true; } } void ScanNode::reset_reg_columns(JtScanCtx* ctx) { for (size_t i = 0; i < reg_column_count(); ++i) { ObExpr* col_expr = ctx->spec_ptr_->column_exprs_.at(reg_col_node(i)->col_info_.output_column_idx_); col_expr->locate_datum_for_write(*ctx->eval_ctx_).reset(); col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); col_expr->get_eval_info(*ctx->eval_ctx_).evaluated_ = true; } } void ObJsonTableOp::destroy() { ObOperator::destroy(); } int RegularCol::check_item_method_json(ObRegCol &col_node, JtScanCtx* ctx) { INIT_SUCC(ret); ObExpr* expr = ctx->spec_ptr_->column_exprs_.at(col_node.col_info_.output_column_idx_); if (col_node.type() == COL_TYPE_QUERY) { if (col_node.expr_param_.dst_type_ != ObVarcharType && col_node.expr_param_.dst_type_ != ObLongTextType && col_node.expr_param_.dst_type_ != ObJsonType) { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_USER_ERROR(OB_ERR_INVALID_DATA_TYPE_RETURNING); } else if (OB_ISNULL(col_node.expr_param_.json_path_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get expr param json path is null", K(ret)); } else if (col_node.expr_param_.json_path_->is_last_func() && OB_FAIL( ObJsonExprHelper::check_item_func_with_return(col_node.expr_param_.json_path_->get_last_node_type(), col_node.expr_param_.dst_type_, expr->datum_meta_.cs_type_, 1))) { if (ret == OB_ERR_INVALID_DATA_TYPE_RETURNING) { ret = OB_ERR_INVALID_DATA_TYPE; LOG_USER_ERROR(OB_ERR_INVALID_DATA_TYPE, "JSON_TABLE"); } LOG_WARN("check item func with return type fail", K(ret)); } else if (OB_FAIL(ObExprJsonQuery::check_item_method_valid_with_wrapper(col_node.expr_param_.json_path_, col_node.expr_param_.wrapper_))) { LOG_WARN("fail to check item method with wrapper", K(ret)); } } else if (col_node.type() == COL_TYPE_VALUE) { if (OB_ISNULL(col_node.expr_param_.json_path_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get expr param json path is null", K(ret)); } else if (col_node.expr_param_.json_path_->is_last_func() && OB_FAIL( ObJsonExprHelper::check_item_func_with_return(col_node.expr_param_.json_path_->get_last_node_type(), col_node.expr_param_.dst_type_, expr->datum_meta_.cs_type_, 0))) { if (ret == OB_ERR_INVALID_DATA_TYPE_RETURNING) { ret = OB_ERR_INVALID_DATA_TYPE; LOG_USER_ERROR(OB_ERR_INVALID_DATA_TYPE, "JSON_TABLE"); } LOG_WARN("check item func with return type fail", K(ret)); } } return ret; } int RegularCol::eval_query_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr, bool& is_null) { INIT_SUCC(ret); ObJsonArray* in = static_cast(col_node.curr_); is_null = false; int8_t use_wrapper = 0; if (in->element_count() == 0) { is_null = true; } else if (in->element_count() == 1 && OB_FAIL(ObExprJsonQuery::get_single_obj_wrapper(col_node.col_info_.wrapper_, use_wrapper, in[0][0]->json_type(), col_node.col_info_.allow_scalar_))) { SET_COVER_ERROR(ctx, ret); LOG_WARN("result can't be returned without array wrapper", K(ret)); } else if (in->element_count() > 1 && OB_FAIL(ObExprJsonQuery::get_multi_scalars_wrapper_type(col_node.col_info_.wrapper_, use_wrapper))) { SET_COVER_ERROR(ctx, ret); LOG_WARN("result can't be returned without array wrapper", K(ret)); } else if (!use_wrapper) { col_node.curr_ = in[0][0]; } return ret; } int RegularCol::eval_value_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr, bool& is_null) { INIT_SUCC(ret); is_null = false; uint8_t is_type_mismatch = 0; ObIJsonBase* in = static_cast(col_node.curr_); if (ob_is_json(col_expr->datum_meta_.type_)) { } else if (in->json_type() == ObJsonNodeType::J_OBJECT || in->json_type() == ObJsonNodeType::J_ARRAY) { ret = OB_ERR_JSON_VALUE_NO_SCALAR; LOG_WARN("result can not be object", K(ret)); SET_COVER_ERROR(ctx, ret); } else if (lib::is_oracle_mode() && OB_FAIL(ObExprJsonValue::deal_item_method_in_seek(in, is_null, col_node.expr_param_.json_path_, &ctx->row_alloc_, is_type_mismatch))) { SET_COVER_ERROR(ctx, ret); LOG_WARN("fail to check res valid" , K(ret)); } else if (lib::is_oracle_mode() && in->json_type() == ObJsonNodeType::J_BOOLEAN && ob_is_number_tc(col_node.col_info_.data_type_.get_obj_type())) { col_node.curr_ = nullptr; is_null = true; ret = OB_ERR_BOOL_CAST_NUMBER; LOG_WARN("boolean cast number cast not support"); SET_COVER_ERROR(ctx, ret); } else if ((in->json_type() == ObJsonNodeType::J_INT || in->json_type() == ObJsonNodeType::J_INT) && (ob_is_datetime_tc(col_node.col_info_.data_type_.get_obj_type()))) { char* res_ptr = ctx->buf; int len = snprintf(ctx->buf, sizeof(ctx->buf), "%ld", in->get_int()); if (len > 0) { ObJsonString* j_string = nullptr; if (OB_ISNULL(j_string = static_cast(ctx->row_alloc_.alloc(sizeof(ObJsonString))))) { ret = OB_ALLOCATE_MEMORY_FAILED; RESET_COVER_CODE(ctx); LOG_WARN("fail to allocate json string node", K(ret)); } else { col_node.curr_ = new(j_string) ObJsonString(ctx->buf, len); } } else { ret = OB_ERR_UNEXPECTED; RESET_COVER_CODE(ctx); LOG_WARN("fail to print int value", K(ret)); } } return ret; } int RegularCol::eval_exist_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr, bool& is_null) { INIT_SUCC(ret); is_null = true; if (ob_is_string_type(col_node.col_info_.data_type_.get_obj_type())) { ObString value("true"); if (lib::is_mysql_mode()) { value.assign_ptr("1", 1); } void* buf = ctx->row_alloc_.alloc(sizeof(ObJsonString)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { col_node.curr_ = static_cast(new(buf)ObJsonString(value.ptr(), value.length())); is_null = false; } } else { void* buf = ctx->row_alloc_.alloc(sizeof(ObJsonInt)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret)); } else { col_node.curr_ = static_cast(new(buf)ObJsonInt(1)); is_null = false; } } return ret; } int RegularCol::eval_xml_scalar_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr) { INIT_SUCC(ret); ObXmlBin *hit = static_cast(col_node.curr_); if (hit->size() > 1 && hit->type() != M_DOCUMENT) { ret = OB_ERR_XQUERY_MULTI_VALUE; SET_COVER_ERROR(ctx, ret); } return ret; } int RegularCol::eval_xml_type_col(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* col_expr) { INIT_SUCC(ret); return ret; } // xmltable expr function int XmlTableFunc::container_at(void* in, void *&out, int32_t pos) { INIT_SUCC(ret); ObXmlBin *t_in = static_cast(in); if (pos < 0 || pos >= t_in->size()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("pos out of range", K(ret), K(pos)); } else { out = t_in->at(pos); } return ret; } int XmlTableFunc::eval_input(ObJsonTableOp &jt, JtScanCtx &ctx, ObEvalCtx &eval_ctx) { INIT_SUCC(ret); common::ObObjMeta& doc_obj_datum = ctx.spec_ptr_->value_expr_->obj_meta_; ObDatumMeta& doc_datum = ctx.spec_ptr_->value_expr_->datum_meta_; ObObjType doc_type = doc_datum.type_; ObCollationType doc_cs_type = doc_datum.cs_type_; ObString j_str; bool is_null = false; ObIMulModeBase *input_node = NULL; if (doc_type == ObNullType) { ret = OB_ITER_END; } else if (ctx.is_xml_table_func()) { if (!doc_obj_datum.is_xml_sql_type() && !ob_is_string_type(doc_type)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("inconsistent datatypes", K(ret), K(ob_obj_type_str(doc_type))); } else { jt.reset_columns(); // get input_node if (OB_FAIL(ObXMLExprHelper::get_xml_base_from_expr(ctx.spec_ptr_->value_expr_, ctx.mem_ctx_, eval_ctx, input_node))) { LOG_WARN("get real data failed", K(ret)); } else { jt.input_ = input_node; } } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid table func", K(ret)); } return ret; } int XmlTableFunc::reset_ctx(ObRegCol &scan_node, JtScanCtx*& ctx) { INIT_SUCC(ret); bool need_eval = false; if (scan_node.node_type() == REG_TYPE) { bool is_datum_data = false; if (scan_node.type() == COL_TYPE_XMLTYPE_XML) { if (scan_node.col_info_.on_empty_ == JSN_VALUE_DEFAULT) { need_eval = true; } } else if (scan_node.type() == COL_TYPE_VAL_EXTRACT_XML) { if (scan_node.col_info_.on_empty_ == JSN_VALUE_DEFAULT) { need_eval = true; is_datum_data = true; } } if (need_eval) { ObExpr* default_expr = ctx->spec_ptr_->emp_default_exprs_.at(scan_node.col_info_.empty_expr_id_); if (OB_FAIL(eval_default_value(ctx, default_expr, scan_node.emp_val_, is_datum_data))) { LOG_WARN("fail to eval default value", K(ret)); } else { scan_node.is_emp_evaled_ = true; scan_node.res_flag_ = ResultType::NOT_DATUM; ObExpr* col_expr = ctx->spec_ptr_->column_exprs_.at(scan_node.col_info_.output_column_idx_); } } } return ret; } int XmlTableFunc::init_ctx(ObRegCol &scan_node, JtScanCtx*& ctx) { INIT_SUCC(ret); bool need_eval = false; // flag of eval default value // init path scan_node.tab_type_ = MulModeTableType::OB_ORA_XML_TABLE_TYPE; if (!scan_node.is_path_evaled_ && OB_ISNULL(scan_node.path_) && (scan_node.node_type() == REG_TYPE || scan_node.node_type() == SCAN_TYPE) && !scan_node.col_info_.path_.empty()) { ObPathExprIter *t_iter = NULL; ObIMulModeBase *doc = nullptr; scan_node.path_ = NULL; void* path_buf = ctx->op_exec_alloc_->alloc(sizeof(ObPathExprIter)); if (OB_ISNULL(doc)) { if (OB_ISNULL(doc = OB_NEWx(ObXmlDocument, ctx->mem_ctx_->allocator_, ObMulModeNodeType::M_CONTENT, ctx->mem_ctx_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create document", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(ObXMLExprHelper::construct_namespace_params(ctx->spec_ptr_->namespace_def_, ctx->default_ns, ctx->context, *ctx->op_exec_alloc_))) { LOG_WARN("fail to get namespace", K(ret)); } else if (OB_ISNULL(path_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate json path buffer", K(ret)); } else { ObPathVarObject *t_ns = static_cast(ctx->context); t_iter = new (path_buf) ObPathExprIter(ctx->op_exec_alloc_, ctx->mem_ctx_->allocator_); if (OB_FAIL(t_iter->init(ctx->xpath_ctx_, scan_node.col_info_.path_, ctx->default_ns, doc, t_ns))) { LOG_WARN("fail to init xpath iterator", K(scan_node.col_info_.path_), K(ctx->default_ns), K(ret)); } else if (OB_FAIL(t_iter->open())) { ret = OB_ERR_PARSE_XQUERY_EXPR; LOG_USER_ERROR(OB_ERR_PARSE_XQUERY_EXPR, t_iter->get_path_str().length(), t_iter->get_path_str().ptr()); LOG_WARN("fail to open xpath iterator", K(ret)); // ObXMLExprHelper::replace_xpath_ret_code(ret); } else if (OB_FAIL(ObXMLExprHelper::check_xpath_valid(*t_iter, scan_node.node_type() == SCAN_TYPE))) { LOG_WARN("check xpath valid failed", K(ret)); } else { scan_node.path_ = t_iter; scan_node.is_path_evaled_ = true; } } } // default value init if (OB_FAIL(ret)) { } else if (scan_node.node_type() == REG_TYPE) { if (!scan_node.is_emp_evaled_) { need_eval = false; bool is_datum_data = false; if (scan_node.type() == COL_TYPE_XMLTYPE_XML) { if (scan_node.col_info_.on_empty_ == JSN_VALUE_DEFAULT) { need_eval = true; } } else if (scan_node.type() == COL_TYPE_VAL_EXTRACT_XML) { if (scan_node.col_info_.on_empty_ == JSN_VALUE_DEFAULT) { need_eval = true; is_datum_data = true; } } if (need_eval) { ObExpr* default_expr = ctx->spec_ptr_->emp_default_exprs_.at(scan_node.col_info_.empty_expr_id_); if (OB_FAIL(eval_default_value(ctx, default_expr, scan_node.emp_val_, is_datum_data))) { LOG_WARN("fail to eval default value", K(ret)); } else { scan_node.is_emp_evaled_ = true; scan_node.res_flag_ = ResultType::NOT_DATUM; ObExpr* col_expr = ctx->spec_ptr_->column_exprs_.at(scan_node.col_info_.output_column_idx_); if (OB_FAIL(check_default_value(ctx, scan_node, col_expr))) { LOG_WARN("check default value failed", K(ret)); } } } } } return ret; } int XmlTableFunc::eval_default_value(JtScanCtx*& ctx, ObExpr*& default_expr, void*& res, bool need_datum) { INIT_SUCC(ret); ObDatum* emp_datum = nullptr; if (OB_FAIL(default_expr->eval(*ctx->eval_ctx_, emp_datum))) { LOG_WARN("failed do cast to returning type.", K(ret)); } else if (!ob_is_xml_sql_type(default_expr->datum_meta_.type_, default_expr->obj_meta_.get_subschema_id())) { res = emp_datum; } else { ObIMulModeBase* xml_base = NULL; if (OB_FAIL(ObXMLExprHelper::get_xml_base(ctx->xpath_ctx_, emp_datum, *ctx->eval_ctx_, xml_base, ObGetXmlBaseType::OB_SHOULD_CHECK))) { LOG_WARN("failed do cast to returning type.", K(ret)); } else if (OB_NOT_NULL(xml_base)) { if (need_datum) { res = emp_datum; } else { res = xml_base; } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null value", K(ret)); } } return ret; } // init_flag int XmlTableFunc::reset_path_iter(ObRegCol &scan_node, void* in, JtScanCtx*& ctx, ScanType init_flag, bool &is_null_value) { INIT_SUCC(ret); ObPathExprIter *t_iter = NULL; ObIMulModeBase *doc = static_cast(in); if (init_flag == COL_NODE_TYPE) { if (OB_ISNULL(doc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("doc can not be null", K(ret)); } else if (scan_node.col_info_.path_.length() == 0) { ret = OB_ERR_PARSE_XQUERY_EXPR; LOG_WARN("path can not be null", K(ret)); } else if (scan_node.col_info_.path_[0] != '/' && doc->size() == 1) { char* extend_start = nullptr; int64_t extend_len = 0; ObXmlBin* bin_doc = nullptr; if (doc->check_extend()) { bin_doc = static_cast(doc); if (OB_FAIL(bin_doc->get_extend(extend_start, extend_len))) { LOG_WARN("fail to get extend", K(ret)); } } if (OB_SUCC(ret)) { doc = doc->at(0); if (OB_NOT_NULL(doc) && OB_NOT_NULL(bin_doc = static_cast(doc)) && OB_NOT_NULL(extend_start) && extend_len > 0 && OB_FAIL(bin_doc->append_extend(extend_start, extend_len))) { LOG_WARN("fail to append extend", K(ret)); } } } } if (OB_FAIL(ret)) { } else if (OB_ISNULL(doc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("doc can not be null", K(ret)); } else if (scan_node.is_path_evaled_ && OB_NOT_NULL(scan_node.path_)) { t_iter = static_cast(scan_node.path_); if (OB_FAIL(t_iter->reset(doc, ctx->mem_ctx_->allocator_))) { LOG_WARN("fail to reset t_iter", K(ret)); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("path_ should not be null", K(ret)); } // scan node get first node if (OB_SUCC(ret) && scan_node.node_type() == SCAN_TYPE) { bool is_null_res = false; if (OB_FAIL(get_iter_value(scan_node, ctx, is_null_res))) { if (ret != OB_ITER_END) { LOG_WARN("fail to get first node", K(ret)); } } else { is_null_value = is_null_res; } } return ret; } int XmlTableFunc::get_iter_value(ObRegCol &col_node, JtScanCtx* ctx, bool &is_null_value) { INIT_SUCC(ret); is_null_value = false; ObPathExprIter *xpath_iter = static_cast(col_node.path_); ObIMulModeBase *node = NULL; if (OB_ISNULL(xpath_iter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("xpath iter can not be null", K(ret)); } else if (OB_FAIL(xpath_iter->get_next_node(node))) { if (ret != OB_ITER_END) { ret = OB_ERR_PARSE_XQUERY_EXPR; LOG_USER_ERROR(OB_ERR_PARSE_XQUERY_EXPR, xpath_iter->get_path_str().length(), xpath_iter->get_path_str().ptr()); LOG_WARN("fail to get next xml node", K(ret)); } } else if (OB_ISNULL(node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("xpath result node is null", K(ret)); } else if (node->type() == ObMulModeNodeType::M_DOCUMENT || node->type() == ObMulModeNodeType::M_CONTENT) { col_node.iter_ = node; col_node.curr_ = node; col_node.cur_pos_ ++; } else if (node->is_tree() && OB_FAIL(ObMulModeFactory::transform(ctx->mem_ctx_, node, BINARY_TYPE, node))) { LOG_WARN("fail to transform to tree", K(ret)); } else { ObBinAggSerializer bin_agg(ctx->mem_ctx_->allocator_, ObBinAggType::AGG_XML, static_cast(M_CONTENT)); ObXmlBin *bin = nullptr; char* extend_start = nullptr; int64_t extend_len = 0; if (OB_ISNULL(bin = static_cast(node))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get bin failed", K(ret)); } else if (bin->check_extend()) { // must be one ans, append extend after final result if (OB_FAIL(bin->get_extend(extend_start, extend_len))) { LOG_WARN("fail to get extend", K(ret)); } else if (OB_FAIL(bin->remove_extend())) { LOG_WARN("fail to remove extend", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(bin_agg.append_key_and_value(bin))) { LOG_WARN("fail to add node in doc", K(ret)); } else { /* seek result can not be next input xml,should add doc node in front */ ObMulModeNodeType type = bin->type(); ObMulModeNodeType node_type = M_CONTENT; if (type == ObMulModeNodeType::M_ELEMENT) { node_type = M_DOCUMENT; } bin_agg.set_header_type(node_type); if (OB_FAIL(bin_agg.serialize())) { LOG_WARN("failed to serialize binary.", K(ret)); } else if (OB_FAIL(ObMulModeFactory::get_xml_base(ctx->mem_ctx_, bin_agg.get_buffer()->string(), ObNodeMemType::BINARY_TYPE, ObNodeMemType::BINARY_TYPE, node))) { LOG_WARN("fail to transform to tree", K(ret)); } else if (OB_NOT_NULL(node) && OB_NOT_NULL(bin = static_cast(node)) && OB_NOT_NULL(extend_start) && OB_FAIL(bin->append_extend(extend_start, extend_len))) { LOG_WARN("fail to append extend", K(ret), K(node)); } else { col_node.iter_ = node; col_node.curr_ = node; col_node.cur_pos_ ++; } } } return ret; } int XmlTableFunc::eval_seek_col(ObRegCol &col_node, void* in, JtScanCtx* ctx, bool &is_null_value, bool &need_cast_res) { INIT_SUCC(ret); ObIMulModeBase *xml_res = NULL; ObPathExprIter *xml_iter = static_cast(col_node.path_); if (OB_ISNULL(xml_iter)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("input containter or xpath can not be null", K(ret)); } else if (OB_ISNULL(in)) { is_null_value = true; col_node.curr_ = nullptr; } else if (OB_FAIL(ObXMLExprHelper::get_xpath_result(*xml_iter, xml_res, ctx->mem_ctx_, col_node.type() == COL_TYPE_XMLTYPE_XML))) { LOG_WARN("xml seek failed", K(col_node.col_info_.path_), K(ret)); SET_COVER_ERROR(ctx, ret); } else if (OB_ISNULL(xml_res) || xml_res->size() == 0) { is_null_value = true; col_node.curr_ = nullptr; } else { is_null_value = false; col_node.curr_ = xml_res; } return ret; } int XmlTableFunc::col_res_type_check(ObRegCol &col_node, JtScanCtx* ctx) { INIT_SUCC(ret); ObObjType obj_type = col_node.col_info_.data_type_.get_obj_type(); JtColType col_type = col_node.type(); if (col_type == COL_TYPE_XMLTYPE_XML) { } return ret; } // default value cast type check bool RegularCol::check_cast_allowed(const ObObjType orig_type, const ObCollationType orig_cs_type, const ObObjType expect_type, const ObCollationType expect_cs_type, const bool is_explicit_cast) { UNUSED(expect_cs_type); bool res = true; ObObjTypeClass ori_tc = ob_obj_type_class(orig_type); ObObjTypeClass expect_tc = ob_obj_type_class(expect_type); bool is_expect_lob_tc = (ObLobTC == expect_tc || ObTextTC == expect_tc); bool is_ori_lob_tc = (ObLobTC == ori_tc || ObTextTC == ori_tc); if (is_oracle_mode()) { if (is_explicit_cast) { // can't cast lob to other type except char/varchar/nchar/nvarchar2/raw. clob to raw not allowed too. if (is_ori_lob_tc) { if (expect_tc == ObJsonTC) { /* oracle mode, json text use lob store */ } else if (ObStringTC == expect_tc) { // do nothing } else if (ObRawTC == expect_tc) { res = CS_TYPE_BINARY == orig_cs_type; } else { res = false; } } // any type to lob type not allowed. if (is_expect_lob_tc) { res = false; } } else { // BINARY FLOAT/DOUBLE not allow cast lob whether explicit if (is_ori_lob_tc) { if (expect_tc == ObFloatTC || expect_tc == ObDoubleTC) { res = false; } } } } return res; } int XmlTableFunc::check_default_value(JtScanCtx* ctx, ObRegCol &col_node, ObExpr* expr) { INIT_SUCC(ret); ObString in_str; if (col_node.col_info_.on_empty_ == JSN_VALUE_DEFAULT) { ObExpr* default_expr = ctx->spec_ptr_->emp_default_exprs_.at(col_node.col_info_.empty_expr_id_); if (static_cast(col_node.col_info_.col_type_) == COL_TYPE_XMLTYPE_XML) { // 检查默认值类型 if (!default_expr->obj_meta_.is_xml_sql_type()) { ret = OB_ERR_INVALID_XML_DATATYPE; LOG_USER_ERROR(OB_ERR_INVALID_XML_DATATYPE, "XMLTYPE", ob_obj_type_str(default_expr->datum_meta_.type_)); } } else if (static_cast(col_node.col_info_.col_type_) == COL_TYPE_VAL_EXTRACT_XML) { if (OB_ISNULL(default_expr) || OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("dat can not be null", K(ret), KP(default_expr), KP(expr)); } if (OB_FAIL(ret)) { } else if (!RegularCol::check_cast_allowed(default_expr->datum_meta_.type_, default_expr->datum_meta_.cs_type_, expr->datum_meta_.type_, expr->datum_meta_.cs_type_, true)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("explicit cast to lob type not allowed", K(ret), K(expr->datum_meta_.type_)); } } } return ret; } int XmlTableFunc::set_on_empty(ObRegCol& col_node, JtScanCtx* ctx, bool &need_cast, bool& is_null) { INIT_SUCC(ret); JtColType col_type = col_node.type(); if (col_type == COL_TYPE_XMLTYPE_XML) { switch (col_node.col_info_.on_empty_) { case JSN_VALUE_IMPLICIT: case JSN_VALUE_NULL: { col_node.curr_ = nullptr; is_null = true; ret = OB_SUCCESS; break; } case JSN_VALUE_DEFAULT: { if (col_node.is_emp_evaled_ && OB_NOT_NULL(col_node.emp_val_)) { col_node.curr_ = col_node.emp_val_; col_node.res_flag_ = ResultType::EMPTY_DATUM; } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null value", K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(ctx->table_func_->cast_to_result(col_node, ctx, false))) { LOG_WARN("fail to cast to res", K(ret)); } else { need_cast = false; is_null = false; } } break; } default: // error_type from get_on_empty_or_error has done range check, do nothing for default break; } } else if (col_type == COL_TYPE_VAL_EXTRACT_XML) { switch (col_node.col_info_.on_empty_) { case JSN_VALUE_IMPLICIT: case JSN_VALUE_NULL: { col_node.curr_ = nullptr; is_null = true; ret = OB_SUCCESS; break; } case JSN_VALUE_DEFAULT: { is_null = false; if (col_node.is_emp_evaled_ && OB_NOT_NULL(col_node.emp_val_)) { col_node.curr_ = col_node.emp_val_; col_node.res_flag_ = ResultType::EMPTY_DATUM; } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get null value", K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(ctx->table_func_->cast_to_result(col_node, ctx, true))) { LOG_WARN("fail to cast to res", K(ret)); } else { need_cast = false; } } break; } default: // error_type from get_on_empty_or_error has done range check, do nothing for default break; } } return ret; } int XmlTableFunc::set_on_error(ObRegCol& col_node, JtScanCtx* ctx, int& ret) { INIT_SUCC(tmp_ret); if (ret == OB_SUCCESS) { } else { const ObJtColInfo& info = col_node.col_info_; if (info.on_error_ == JSN_VALUE_ERROR || info.on_error_ == JSN_VALUE_IMPLICIT) { EVAL_COVER_CODE(ctx, ret) ; if (OB_SUCC(ret) && ctx->is_need_end_) { ret = OB_ITER_END; } } } return tmp_ret; } int XmlTableFunc::cast_to_result(ObRegCol& col_node, JtScanCtx* ctx, bool enable_error, bool is_pack_result) { INIT_SUCC(ret); UNUSED(enable_error); UNUSED(is_pack_result); JtColType col_type = col_node.type(); ObJtColInfo& col_info = col_node.get_column_def(); bool is_truncate = static_cast(col_info.truncate_); ObExpr* expr = ctx->spec_ptr_->column_exprs_.at(col_info.output_column_idx_); ObDatum& res = expr->locate_datum_for_write(*ctx->eval_ctx_); ctx->res_obj_ = &res; ObXmlBin *doc = static_cast(col_node.curr_); ObObjType dst_type = expr->datum_meta_.type_; ObCollationType coll_type = expr->datum_meta_.cs_type_; ObAccuracy accuracy = col_info.data_type_.get_accuracy(); ObCollationType dst_coll_type = col_info.data_type_.get_collation_type(); ObCollationType in_coll_type = ctx->is_charset_converted_ ? CS_TYPE_UTF8MB4_BIN : ctx->spec_ptr_->value_expr_->datum_meta_.cs_type_; ObCollationLevel dst_coll_level = col_info.data_type_.get_collation_level(); ObString xml_str; // 这里是不是不应该根据列定义划分,而是根据类型划分,,xml列就使用extract的逻辑,其他列就调用cast逻辑。 switch(col_type) { case COL_TYPE_XMLTYPE_XML : { ObString blob_locator; if (OB_FAIL(doc->get_raw_binary(xml_str, &ctx->row_alloc_))) { LOG_WARN("failed to get bin", K(ret)); } else if (OB_FAIL(ObXMLExprHelper::pack_binary_res(*expr, *ctx->eval_ctx_, xml_str, blob_locator))) { LOG_WARN("pack binary res failed", K(ret)); } else { res.set_string(blob_locator.ptr(), blob_locator.length()); } break; } case COL_TYPE_VAL_EXTRACT_XML : { if (col_node.res_flag_ == ResultType::NOT_DATUM) { // xmltype to unxmltype if (OB_FAIL(ObXMLExprHelper::extract_xml_text_node(ctx->mem_ctx_, doc, xml_str))) { LOG_WARN("fail to extract xml text node", K(ret), K(xml_str)); } else if (OB_FAIL(ObXMLExprHelper::cast_to_res(ctx->row_alloc_, xml_str, *expr, *ctx->eval_ctx_, res))) { LOG_WARN("fail to cast to res", K(ret), K(xml_str)); } } else { // use datum cast non xmltype, current only use for default value ObExpr* default_expr = ctx->spec_ptr_->emp_default_exprs_.at(col_node.col_info_.empty_expr_id_); ObDatum *src = static_cast(col_node.curr_); col_node.res_flag_ = NOT_DATUM; // reset flag; ObObj src_obj; bool need_check_acc = false; if (ob_is_xml_sql_type(default_expr->datum_meta_.type_, default_expr->obj_meta_.get_subschema_id())) { need_check_acc = true; } if (src->is_null()) { res.set_null(); } else if (OB_FAIL(src->to_obj(src_obj, default_expr->obj_meta_, default_expr->obj_datum_map_))) { LOG_WARN("fail cast datum to obj", K(ret)); } else if (OB_FAIL(ObXMLExprHelper::cast_to_res(ctx->row_alloc_, src_obj, *expr, *ctx->eval_ctx_, res, need_check_acc))) { LOG_WARN("fail to cast to res", K(ret), K(xml_str)); } } break; } default : { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid column type", K(ret), K(col_type)); break; } } return ret; } // scan node function implement int ScanNode::assign(const ScanNode& other) { INIT_SUCC(ret); if (OB_FAIL(reg_col_defs_.assign(other.reg_col_defs_))) { LOG_WARN("fail to assign col defs.", K(ret), K(other.reg_col_defs_.count())); } else if (OB_FAIL(child_idx_.assign(other.child_idx_))) { LOG_WARN("fail to assign child idx defs.", K(ret), K(other.child_idx_.count())); } else { seek_node_ = other.seek_node_; } return ret; } int JoinNode::assign(const JoinNode& other) { INIT_SUCC(ret); right_ = other.right_; left_ = other.left_; return ret; } int ScanNode::add_reg_column_node(ObRegCol* node, bool add_idx) { INIT_SUCC(ret); if (OB_FAIL(reg_col_defs_.push_back(node))) { LOG_WARN("fail to store node ptr", K(ret), K(reg_col_defs_.count())); } return ret; } // basic function int ObRegCol::open(JtScanCtx* ctx) { INIT_SUCC(ret); if (OB_FAIL(ctx->table_func_->init_ctx(*this, ctx))) { LOG_WARN("fail to init variable" , K(ret)); } else { ord_val_ = -1; cur_pos_ = -1; } return ret; } int ObRegCol::reset(JtScanCtx* ctx) { INIT_SUCC(ret); if (OB_FAIL(ctx->table_func_->reset_ctx(*this, ctx))) { LOG_WARN("fail to init variable" , K(ret)); } else { ord_val_ = -1; cur_pos_ = -1; } return ret; } int UnionNode::open(JtScanCtx* ctx) { INIT_SUCC(ret); if (OB_FAIL(ObMultiModeTableNode::open(ctx))) { LOG_WARN("fail to open column node.", K(ret)); } else if (left_ && OB_FAIL(left_->open(ctx))) { LOG_WARN("fail to open left node.", K(ret)); } else if (right_ && OB_FAIL(right_->open(ctx))) { LOG_WARN("fail to open right node.", K(ret)); } return ret; } int UnionNode::reset(JtScanCtx* ctx) { INIT_SUCC(ret); if (OB_FAIL(ObMultiModeTableNode::reset(ctx))) { LOG_WARN("fail to reset base node", K(ret)); } else if (left_ && OB_FAIL(left_->reset(ctx))) { LOG_WARN("fail to reset left child", K(ret)); } else if (right_ && OB_FAIL(right_->reset(ctx))) { LOG_WARN("fail to reset right child", K(ret)); } else { is_left_iter_end_ = false; is_right_iter_end_ = true; } return ret; } int ScanNode::open(JtScanCtx* ctx) { INIT_SUCC(ret); if (OB_FAIL(ObMultiModeTableNode::open(ctx))) { LOG_WARN("fail to open column node.", K(ret)); } else if (OB_FAIL(seek_node_.open(ctx))) { LOG_WARN("fail to open seek node.", K(ret)); } else { for (int i = 0; OB_SUCC(ret) && i < reg_col_defs_.count(); ++i) { ObRegCol* node = reg_col_defs_.at(i); if (OB_FAIL(node->open(ctx))) { LOG_WARN("fail to open reg node.", K(ret)); } } } return ret; } int ScanNode::reset(JtScanCtx* ctx) { INIT_SUCC(ret); if (OB_FAIL(ObMultiModeTableNode::reset(ctx))) { LOG_WARN("fail to reset base node", K(ret)); } else if (OB_FAIL(seek_node_.reset(ctx))) { LOG_WARN("fail to reset seek node", K(ret)); } for (int i = 0; OB_SUCC(ret) && i < reg_col_defs_.count(); ++i) { ObRegCol* node = reg_col_defs_.at(i); ret = node->reset(ctx); } return ret; } void ObMultiModeTableNode::destroy() { // do nothing } void ObRegCol::destroy() { // path destory if (is_path_evaled_ && OB_NOT_NULL(path_)) { is_path_evaled_ = false; if (tab_type_ == OB_ORA_XML_TABLE_TYPE) { ObPathExprIter* tmp_iter = static_cast(path_); tmp_iter->~ObPathExprIter(); } else if (tab_type_ == OB_ORA_JSON_TABLE_TYPE) { // do nothing current ObJsonPath* json_path = static_cast(path_); json_path->~ObJsonPath(); } } } void UnionNode::destroy() { if (OB_NOT_NULL(left_)) { left_->destroy(); } if (OB_NOT_NULL(right_)) { right_->destroy(); } } void ScanNode::destroy() { seek_node_.destroy(); for (size_t i = 0; i < reg_col_defs_.count(); ++i) { reg_col_defs_.at(i)->destroy(); } reg_col_defs_.reset(); child_idx_.reset(); } // common logical : iter int ObRegCol::eval_regular_col(void *in, JtScanCtx* ctx, bool& is_null_value) { INIT_SUCC(ret); JtColType col_type = type(); is_null_value = false; bool is_null_res = false; ObExpr* col_expr = ctx->spec_ptr_->column_exprs_.at(col_info_.output_column_idx_); ctx->res_obj_ = &col_expr->locate_datum_for_write(*ctx->eval_ctx_); bool need_cast_res = true; bool enable_error = true; if (lib::is_mysql_mode() && OB_ISNULL(in)) { is_null_value = true; need_cast_res = false; curr_ = nullptr; col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); } else if (col_type == COL_TYPE_ORDINALITY || col_type == COL_TYPE_ORDINALITY_XML) { if (OB_ISNULL(in)) { col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); } else { col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_int(ctx->ord_val_); } col_expr->get_eval_info(*ctx->eval_ctx_).evaluated_ = true; } else { if (OB_FAIL(ctx->table_func_->col_res_type_check(*this, ctx))) { LOG_WARN("check column res type failed", K(ret), K(col_info_.data_type_), K(col_info_.col_type_)); } else if (OB_ISNULL(in)) { is_null_value = true; curr_ = nullptr; EVAL_COVER_CODE(ctx, ret); } else if (OB_FAIL(ctx->table_func_->reset_path_iter(*this, in, ctx, ScanType::COL_NODE_TYPE, is_null_res))) { RESET_COVER_CODE(ctx); LOG_WARN("fail to init func path", K(ret)); } else if (is_null_res) { is_null_value = true; } else if (OB_FAIL(ctx->table_func_->eval_seek_col(*this, in, ctx, is_null_res, need_cast_res))) { SET_COVER_ERROR(ctx, ret); LOG_WARN("json seek failed", K(col_info_.path_), K(ret)); } else if (curr_ == nullptr || is_null_res) { is_null_value = true; } else { is_null_value = false; if (col_type == COL_TYPE_QUERY) { if (OB_FAIL(RegularCol::eval_query_col(*this, ctx, col_expr, is_null_value))) { LOG_WARN("fail to eval json query value", K(ret), K(col_type)); } } else if (col_type == COL_TYPE_VALUE) { if (OB_FAIL(RegularCol::eval_value_col(*this, ctx, col_expr, is_null_value))) { LOG_WARN("fail to eval json value value", K(ret), K(col_type)); } } else if (col_type == COL_TYPE_EXISTS) { if (OB_FAIL(RegularCol::eval_exist_col(*this, ctx, col_expr, is_null_value))) { LOG_WARN("fail to eval json exist value", K(ret), K(col_type)); } } else if (col_type == COL_TYPE_XMLTYPE_XML) { if (OB_FAIL(RegularCol::eval_xml_type_col(*this, ctx, col_expr))) { LOG_WARN("fail to eval xml type value", K(ret), K(col_type)); } } else if (col_type == COL_TYPE_VAL_EXTRACT_XML) { if (OB_FAIL(RegularCol::eval_xml_scalar_col(*this, ctx, col_expr))) { LOG_WARN("fail to eval xml scalar value", K(ret), K(col_type)); } } } } if (OB_FAIL(ret)) { // deal empty value } else if (col_type == COL_TYPE_EXISTS || col_type == COL_TYPE_QUERY || col_type == COL_TYPE_VALUE || col_type == COL_TYPE_XMLTYPE_XML || col_type == COL_TYPE_VAL_EXTRACT_XML) { if (is_null_value) { if (OB_FAIL(ctx->table_func_->set_on_empty(*this, ctx, need_cast_res, is_null_value))) { LOG_WARN("fail to process on empty", K(ret)); } } else if (ctx->is_json_table_func() && curr_ && NOT_DATUM == res_flag_ && static_cast(curr_)->json_type() == ObJsonNodeType::J_NULL && (!static_cast(curr_)->is_real_json_null(static_cast(curr_)) || lib::is_mysql_mode())) { curr_ = nullptr; } } // deal error value if (OB_FAIL(ret)) { if (ctx->is_cover_error_) { enable_error = false; int tmp_ret = ctx->table_func_->set_on_error(*this, ctx, ret); if (tmp_ret != OB_SUCCESS) { LOG_WARN("failed to set error val.", K(tmp_ret)); } } } // cast_to_res if (OB_FAIL(ret)) { } else if (col_type == COL_TYPE_EXISTS || col_type == COL_TYPE_QUERY || col_type == COL_TYPE_VALUE || col_type == COL_TYPE_XMLTYPE_XML || col_type == COL_TYPE_VAL_EXTRACT_XML) { if (OB_ISNULL(curr_)) { is_null_value = true; col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); } else if (need_cast_res && OB_FAIL(ctx->table_func_->cast_to_result(*this, ctx, enable_error))) { LOG_WARN("failed to do cast to res type", K(ret)); } else if (OB_ISNULL(curr_)) { is_null_value = true; } } if (OB_SUCC(ret)) { res_flag_ = NOT_DATUM; col_expr->get_eval_info(*ctx->eval_ctx_).evaluated_ = true; } return ret; } int RegularCol::check_default_value_inner_oracle(JtScanCtx* ctx, ObJtColInfo &col_info, ObExpr* col_expr, ObExpr* default_expr) { INIT_SUCC(ret); ObString in_str; ObDatum *emp_datum = nullptr; if (OB_FAIL(default_expr->eval(*ctx->eval_ctx_, emp_datum))) { LOG_WARN("failed do cast to returning type.", K(ret)); } else { in_str.assign_ptr(emp_datum->ptr_, emp_datum->len_); } if (OB_FAIL(ret)) { } else if (default_expr->datum_meta_.type_ == ObNullType && ob_is_string_type(col_info.data_type_.get_obj_type())) { ret = OB_ERR_DEFAULT_VALUE_NOT_LITERAL; LOG_WARN("default value not match returing type", K(ret)); } else if (OB_FAIL(ObJsonExprHelper::pre_default_value_check(col_expr->datum_meta_.type_, in_str, default_expr->datum_meta_.type_, col_info.data_type_.get_accuracy().get_length()))) { LOG_WARN("default value pre check fail", K(ret), K(in_str)); } else { if (ob_obj_type_class(col_expr->datum_meta_.type_) == ob_obj_type_class(default_expr->datum_meta_.type_) && OB_FAIL(ObExprJsonValue::check_default_val_accuracy(col_info.data_type_.get_accuracy(), default_expr->datum_meta_.type_, emp_datum))) { LOG_WARN("fail to check accuracy", K(ret)); } } return ret; } int ScanNode::get_next_iter(void* in, JtScanCtx* ctx, bool& is_null_value) { INIT_SUCC(ret); is_null_value = false; bool is_null_iter = false; if (!is_evaled_ || in_ != in) { in_ = in; is_null_result_ = false; if (OB_ISNULL(in_)) { is_null_value = is_null_result_ = true; seek_node_.curr_ = seek_node_.iter_ = nullptr; seek_node_.cur_pos_ = 0; seek_node_.total_ = 0; } else if (OB_FAIL(ctx->table_func_->reset_path_iter(seek_node_, in_, ctx, ScanType::SCAN_NODE_TYPE, is_null_iter))) { // reset path & get first result RESET_COVER_CODE(ctx); LOG_WARN("fail to init path", K(ret), K(ctx->spec_ptr_->table_type_), K(ctx->table_func_)); } else if (is_null_iter) { is_null_value = is_null_result_ = true; seek_node_.curr_ = seek_node_.iter_ = nullptr; seek_node_.total_ = 1; seek_node_.cur_pos_ = 0; // 1. if root node seek result is NULL, but input(in) not null,then return end. if (seek_node_.col_info_.parent_id_ == common::OB_INVALID_ID || (ctx->jt_op_->get_root_param() == in // 2. if path == '$' && root scan node not have regular column, && ctx->jt_op_->get_root_entry()->get_scan_node()->reg_column_count() == 0 && ctx->jt_op_->get_root_entry()->get_scan_node() == this)) { ret = OB_ITER_END; } } if (OB_SUCC(ret)) { is_evaled_= true; seek_node_.cur_pos_ = 0; } } else { is_null_iter = false; if (OB_FAIL(ctx->table_func_->get_iter_value(seek_node_, ctx, is_null_iter))) { if (ret == OB_ITER_END) { seek_node_.curr_ = seek_node_.iter_ = nullptr; } else { LOG_WARN("fail to get seek value", K(ret)); } } else if (is_null_iter) { is_null_value = is_null_result_ = true; seek_node_.curr_ = seek_node_.iter_ = nullptr; } } return ret; } int ScanNode::get_next_row(void* in, JtScanCtx* ctx, bool& is_null_value) { INIT_SUCC(ret); bool is_empty_node = false; is_null_value = false; if (OB_FAIL(get_next_iter(in, ctx, is_empty_node))) { LOG_WARN("fail to get current node", K(ret)); } is_null_value = is_empty_node; // need reset column reset_reg_columns(ctx); // eval regular column if (OB_SUCC(ret)) { uint32_t reg_count = reg_col_defs_.count(); bool tmp_is_null = false; for (uint32_t i = 0; OB_SUCC(ret) && i < reg_count && is_evaled_; ++i) { ObRegCol* cur_node = reg_col_defs_.at(i); if (cur_node->type() == COL_TYPE_ORDINALITY || cur_node->type() == COL_TYPE_ORDINALITY_XML) { ctx->ord_val_ = seek_node_.cur_pos_ + 1; } if (OB_FAIL(cur_node->eval_regular_col(seek_node_.iter_, ctx, tmp_is_null))) { LOG_WARN("fail to get regular column value", K(ret)); } else { is_null_value &= tmp_is_null; } } // eval scan node in join node } return ret; } int JoinNode::get_next_row(void* in, JtScanCtx* ctx, bool& is_null_value) { INIT_SUCC(ret); is_null_value = false; ObMultiModeTableNode* left_node = left(); ObMultiModeTableNode* right_node = right(); bool is_left_null = false; bool is_right_null = false; if (!is_right_iter_end_) { // right node can expand more value, } else if (OB_NOT_NULL(left_)) { is_right_iter_end_ = false; ret = left_node->get_next_row(in, ctx, is_left_null); if (OB_FAIL(ret) && ret != OB_ITER_END) { LOG_WARN("fail to get next row", K(ret)); } else if (OB_SUCC(ret)) { is_null_value = is_left_null; } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get iter node", K(ret)); } bool is_sub_result_null = false; // nested child result is null then if (OB_SUCC(ret)) { // child : join ->right child_ = union node if (right_node) { if (OB_FAIL(right_node->get_next_row(get_curr_iter_value(), ctx, is_sub_result_null))) { if (OB_FAIL(ret) && ret != OB_ITER_END) { LOG_WARN("fail to get column value", K(ret)); } else if (ret == OB_ITER_END) { is_right_iter_end_ = true; } } else if (OB_SUCC(ret)) { is_null_value &= is_sub_result_null; if (is_sub_result_null) { is_right_iter_end_ = true; } } } else { is_right_iter_end_ = true; } } if (OB_SUCC(ret) && OB_ISNULL(get_curr_iter_value()) && ctx->jt_op_->get_root_entry() == this) { ret = OB_ITER_END; } else if (OB_FAIL(ret) && is_right_iter_end_) { // nested column evaled finis should get next iter if (!is_evaled_) { ret = OB_SUCCESS; // ignore only one null result } else if (OB_FAIL(get_next_row(in, ctx, is_null_value))) { if (ret != OB_ITER_END) { LOG_WARN("fail to get value", K(ret)); } } } else if (OB_FAIL(ret)) { // if return fail, need reset flag is_right_iter_end_ = true; } is_evaled_ = true; return ret; } int UnionNode::get_next_row(void* in, JtScanCtx* ctx, bool& is_null_value) { INIT_SUCC(ret); ObMultiModeTableNode* left_node = left(); ObMultiModeTableNode* right_node = right(); is_null_value = false; bool is_left_null = false; bool is_right_null = false; if (in != in_) { is_left_iter_end_ = false; } if (OB_NOT_NULL(left_node) && !is_left_iter_end_) { ret = left_node->get_next_row(in, ctx, is_left_null); if (OB_FAIL(ret)) { if (ret != OB_ITER_END) { LOG_WARN("fail to get next row", K(ret)); } else { is_left_iter_end_ = true; } } else { is_null_value = is_left_null; if (is_left_null) { is_left_iter_end_ = true; } } } else { ret = OB_ITER_END; } if (OB_SUCC(ret)) { if (is_left_null && OB_NOT_NULL(right_node)) { ret = right_node->get_next_row(in, ctx, is_right_null); if (OB_FAIL(ret) && ret != OB_ITER_END) { LOG_WARN("fail to get next row", K(ret)); } else if (OB_SUCC(ret)) { if (!is_right_null) { is_null_value = false; } } } } else if (OB_NOT_NULL(right_node) && (ret == OB_ITER_END)) { ret = right_node->get_next_row(in, ctx, is_right_null); if (OB_FAIL(ret) && ret != OB_ITER_END) { LOG_WARN("fail to get next row", K(ret)); } else if (OB_SUCC(ret) && is_right_null) { if (in_ == in) { ret = OB_ITER_END; } } else if (OB_SUCC(ret) && !is_right_null) { is_null_value = false; } } in_ = in; return ret; } // json/xml table function inner int ObJsonTableOp::inner_get_next_row() { INIT_SUCC(ret); bool is_root_null = false; if (!(jt_ctx_.is_xml_table_func() || jt_ctx_.is_json_table_func())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unsupport table function", K(ret)); } else if (is_evaled_) { clear_evaluated_flag(); if (OB_FAIL(root_->get_next_row(input_, &jt_ctx_, is_root_null))) { if (ret != OB_ITER_END) { LOG_WARN("failed to open get next row.", K(ret)); } } } else { clear_evaluated_flag(); if (OB_FAIL(jt_ctx_.table_func_->eval_input(*this, jt_ctx_, *jt_ctx_.eval_ctx_))) { // get input value if (ret != OB_ITER_END) { LOG_WARN("fail to get input val", K(ret)); } } else if (OB_FAIL(root_->get_next_row(input_, &jt_ctx_, is_root_null))) { if (ret != OB_ITER_END) { LOG_WARN("fail to get next row", K(ret)); } } else { is_evaled_ = true; } } return ret; } int JsonTableFunc::col_res_type_check(ObRegCol &col_node, JtScanCtx* ctx) { INIT_SUCC(ret); ObObjType obj_type = col_node.col_info_.data_type_.get_obj_type(); JtColType col_type = col_node.type(); if (lib::is_mysql_mode()) { } else if (col_type == COL_TYPE_EXISTS) { if (ob_is_string_type(obj_type) || ob_is_numeric_type(obj_type) || ob_is_integer_type(obj_type)) { // do nothing } else if (ob_is_json_tc(obj_type)) { ret = OB_ERR_USAGE_KEYWORD; LOG_WARN("invalid usage of keyword EXISTS", K(ret)); } else { ret = OB_ERR_NON_NUMERIC_CHARACTER_VALUE; SET_COVER_ERROR(ctx, ret); } } else if (col_type == COL_TYPE_QUERY ) { // do nothing } return ret; } int JsonTableFunc::check_default_value(JtScanCtx* ctx, ObRegCol &col_node, ObExpr* expr) { INIT_SUCC(ret); if (lib::is_mysql_mode()) { // in mysql mode, should check default value with parse json if (OB_FAIL(RegularCol::check_default_value_mysql(col_node, ctx, expr))) { LOG_WARN("fail to check default value in mysql", K(ret)); } } else { // oracle mode can use datum as result if (OB_FAIL(RegularCol::check_default_value_oracle(ctx, col_node.col_info_, expr))) { LOG_WARN("fail to check default value in oracle", K(ret)); } } return ret; } int RegularCol::parse_default_value_2json(ObExpr* default_expr, JtScanCtx* ctx, ObDatum*& tmp_datum, ObIJsonBase *&res) { INIT_SUCC(ret); ObObjType val_type = default_expr->datum_meta_.type_; ObCollationType cs_type = default_expr->datum_meta_.cs_type_; ObDatum converted_datum; converted_datum.set_datum(*tmp_datum); ObString origin_str = converted_datum.get_string(); // convert string charset if needed if (ob_is_string_type(val_type) && ObCharset::charset_type_by_coll(cs_type) != CHARSET_UTF8MB4) { ObString converted_str; if (OB_FAIL(ObExprUtil::convert_string_collation(origin_str, cs_type, converted_str, CS_TYPE_UTF8MB4_BIN, ctx->row_alloc_))) { LOG_WARN("convert string collation failed", K(ret), K(cs_type), K(origin_str.length())); } else { converted_datum.set_string(converted_str); cs_type = CS_TYPE_UTF8MB4_BIN; } } origin_str = converted_datum.get_string(); if (OB_SUCC(ret) && OB_FAIL(ObJsonExprHelper::get_json_val(converted_datum, *ctx->exec_ctx_, default_expr, ctx->op_exec_alloc_, val_type, cs_type, res))) { LOG_WARN("fail to parse default value", K(ret)); } return ret; } int RegularCol::check_default_value_mysql(ObRegCol &col_node, JtScanCtx* ctx, ObExpr* expr) { INIT_SUCC(ret); ctx->is_cover_error_ = false; ObIJsonBase* j_res = NULL; if (col_node.col_info_.on_empty_ == JSN_VALUE_DEFAULT) { j_res = static_cast(col_node.emp_val_); ObExpr* default_expr = ctx->spec_ptr_->emp_default_exprs_.at(col_node.col_info_.empty_expr_id_); if (OB_FAIL(RegularCol::check_default_value_inner_mysql(ctx, col_node, default_expr, expr, j_res))) { LOG_WARN("fail to check empty default value", K(ret)); } } if (OB_SUCC(ret) && col_node.col_info_.on_error_ == JSN_VALUE_DEFAULT) { j_res = static_cast(col_node.err_val_); ObExpr* default_expr = ctx->spec_ptr_->err_default_exprs_.at(col_node.col_info_.error_expr_id_); if (OB_FAIL(RegularCol::check_default_value_inner_mysql(ctx, col_node, default_expr, expr, j_res))) { LOG_WARN("fail to check error default value", K(ret)); } } return ret; } int RegularCol::check_default_value_inner_mysql(JtScanCtx* ctx, ObRegCol &col_node, ObExpr* default_expr, ObExpr* expr, ObIJsonBase* j_base) { INIT_SUCC(ret); ObDatum res; ObDatum* tmp_datum = nullptr; uint8_t is_type_mismatch = 0; ObAccuracy accuracy = col_node.col_info_.data_type_.get_accuracy(); char col_str[col_node.col_info_.col_name_.length()]; ObObjType dst_type = expr->datum_meta_.type_; ObJsonCastParam cast_param(dst_type, default_expr->datum_meta_.cs_type_, expr->datum_meta_.cs_type_, false); cast_param.is_only_check_ = true; cast_param.is_json_table_ = true; cast_param.rt_expr_ = expr; if (OB_ISNULL(j_base)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("json data can not be null", K(ret)); } else if ((dst_type != ObJsonType && !j_base->is_json_scalar(j_base->json_type()))) { ret = OB_INVALID_DEFAULT; LOG_USER_ERROR(OB_INVALID_DEFAULT, col_node.col_info_.col_name_.length(), col_node.col_info_.col_name_.ptr()); } else if (OB_FAIL(ObJsonUtil::cast_to_res(&ctx->row_alloc_, *ctx->eval_ctx_, j_base, accuracy, cast_param, res, is_type_mismatch))) { ret = OB_OPERATE_OVERFLOW; databuff_printf(col_str, col_node.col_info_.col_name_.length(), 0, "%s", col_node.col_info_.col_name_.length(), col_node.col_info_.col_name_.ptr()); LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "JSON_TABLE", col_str); } return ret; } int RegularCol::check_default_value_oracle(JtScanCtx* ctx, ObJtColInfo &col_info, ObExpr* expr) { INIT_SUCC(ret); if (static_cast(col_info.col_type_) == COL_TYPE_VALUE) { if (col_info.on_empty_ == JSN_VALUE_DEFAULT) { ObExpr* default_expr = ctx->spec_ptr_->emp_default_exprs_.at(col_info.empty_expr_id_); if (OB_FAIL(RegularCol::check_default_value_inner_oracle(ctx, col_info, expr, default_expr))) { LOG_WARN("fail to check empty default value in oracle", K(ret)); } } if (OB_SUCC(ret) && col_info.on_error_ == JSN_VALUE_DEFAULT) { ObExpr* default_expr = ctx->spec_ptr_->err_default_exprs_.at(col_info.error_expr_id_); if (OB_FAIL(RegularCol::check_default_value_inner_oracle(ctx, col_info, expr, default_expr))) { LOG_WARN("fail to check error default value in oracle", K(ret)); } } } return ret; } int JsonTableFunc::set_expr_exec_param(ObRegCol& col_node, JtScanCtx* ctx) { INIT_SUCC(ret); ObExpr* expr = ctx->spec_ptr_->column_exprs_.at(col_node.col_info_.output_column_idx_); ObObjType dst_type = expr->datum_meta_.type_; ObAccuracy accuracy = col_node.col_info_.data_type_.get_accuracy(); col_node.expr_param_.truncate_ = col_node.col_info_.truncate_; col_node.expr_param_.format_json_ = col_node.col_info_.format_json_; col_node.expr_param_.wrapper_ = col_node.col_info_.wrapper_; col_node.expr_param_.empty_type_ = col_node.col_info_.on_empty_; col_node.expr_param_.error_type_ = col_node.col_info_.on_error_; col_node.expr_param_.accuracy_ = accuracy; col_node.expr_param_.dst_type_ = dst_type; col_node.expr_param_.pretty_type_ = 0; col_node.expr_param_.ascii_type_ = 0; col_node.expr_param_.scalars_type_ = col_node.col_info_.allow_scalar_; if (OB_FAIL(col_node.expr_param_.on_mismatch_.push_back(col_node.col_info_.on_mismatch_))) { LOG_WARN("fail to push mismatch value into array", K(ret)); } else if (OB_FAIL(col_node.expr_param_.on_mismatch_type_.push_back(col_node.col_info_.on_mismatch_type_))) { LOG_WARN("fail to push mismatch type into array", K(ret)); } return ret; } int JsonTableFunc::set_on_empty(ObRegCol& col_node, JtScanCtx* ctx, bool &need_cast, bool& is_null) { INIT_SUCC(ret); JtColType col_type = col_node.type(); bool is_cover_by_error = true; if (col_type == COL_TYPE_QUERY) { is_null = false; bool is_json_arr = false; bool is_json_obj = false; if (OB_FAIL(ObExprJsonQuery::get_empty_option(is_cover_by_error, col_node.col_info_.on_empty_, is_null, is_json_arr, is_json_obj))) { if (is_cover_by_error) { SET_COVER_ERROR(ctx, ret); } LOG_WARN("empty cluase report error res", K(ret)); } else if (is_null) { col_node.curr_ = nullptr; ret = OB_SUCCESS; } else if (is_json_arr) { col_node.curr_ = ctx->jt_op_->get_js_array(); } else if (is_json_obj) { col_node.curr_ = ctx->jt_op_->get_js_object(); } } else if (col_type == COL_TYPE_VALUE) { is_null = false; ObDatum *t_res = NULL; if (OB_FAIL(ObExprJsonValue::get_empty_option(t_res, is_cover_by_error, col_node.col_info_.on_empty_, static_cast(col_node.err_val_), is_null))) { if (is_cover_by_error) { SET_COVER_ERROR(ctx, ret); } LOG_WARN("empty clause report error opt", K(ret)); } else if (is_null) { col_node.curr_ = nullptr; } else { if (OB_ISNULL(col_node.emp_val_) || !col_node.is_emp_evaled_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get err_val", K(ret), K(col_node.is_emp_evaled_)); } else if (lib::is_oracle_mode()) { col_node.curr_ = col_node.emp_val_; col_node.res_flag_ = ResultType::EMPTY_DATUM; } else { // mysql mode col_node.curr_ = col_node.emp_val_; col_node.res_flag_ = ResultType::NOT_DATUM; } } } else if (col_type == COL_TYPE_EXISTS) { bool res_val = false; if (OB_FAIL(ObExprJsonExists::get_empty_option(col_node.col_info_.on_empty_, res_val))) { LOG_WARN("empty clause report error opt", K(ret)); } else if (!res_val) { // result will return false currently, not return true if (ob_is_string_type(col_node.col_info_.data_type_.get_obj_type())) { ObString value = lib::is_oracle_mode() ? "false" : "0"; void* buf = ctx->row_alloc_.alloc(sizeof(ObJsonString)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { col_node.curr_ = static_cast(new(buf)ObJsonString(value.ptr(), value.length())); is_null = false; } } else { void* buf = ctx->row_alloc_.alloc(sizeof(ObJsonInt)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret)); } else { col_node.curr_ = static_cast(new(buf)ObJsonInt(0)); is_null = false; } } } } return ret; } int JsonTableFunc::set_on_error(ObRegCol& col_node, JtScanCtx* ctx, int& ret) { INIT_SUCC(tmp_ret); if (ret == OB_SUCCESS) { } else { bool is_null = false; const ObJtColInfo& info = col_node.col_info_; JtColType col_type = col_node.type(); ObIJsonBase* t_val = nullptr; bool has_default_val = false; ObExpr* expr = ctx->spec_ptr_->column_exprs_.at(col_node.col_info_.output_column_idx_); if (col_type == COL_TYPE_VALUE) { ObExprJsonValue::get_error_option(info.on_error_, is_null, has_default_val); if (is_null) { col_node.curr_ = nullptr; ret = ctx->is_need_end_ ? OB_ITER_END : OB_SUCCESS; } else if (has_default_val) { if (OB_ISNULL(col_node.err_val_) || !col_node.is_err_evaled_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get err_val", K(ret)); } else if (lib::is_oracle_mode()) { col_node.curr_ = col_node.err_val_; col_node.res_flag_ = ResultType::ERROR_DATUM; ret = OB_SUCCESS; } else { // mysql mode col_node.curr_ = col_node.err_val_; col_node.res_flag_ = ResultType::NOT_DATUM; ret = OB_SUCCESS; } } else if (ret != OB_SUCCESS) { EVAL_COVER_CODE(ctx, ret) ; if (ctx->is_need_end_ && OB_SUCC(ret)) { ret = OB_ITER_END; } } } else if (col_type == COL_TYPE_QUERY) { t_val = NULL; if (col_node.expr_param_.error_type_ == JSN_QUERY_ERROR) { } else if (OB_FAIL(ObExprJsonQuery::get_error_option(col_node.expr_param_.error_type_, t_val, ctx->jt_op_->get_js_array(), ctx->jt_op_->get_js_object(), is_null))) { LOG_WARN("error option report error", K(ret)); } else if (is_null) { if (OB_FAIL(ObExprJsonQuery::get_mismatch_option(col_node.expr_param_.on_mismatch_[0], ctx->error_code_))) { LOG_WARN("mismatch clause will report error", K(ret)); } else { is_null = true; col_node.curr_ = nullptr; ret = ctx->is_need_end_ ? OB_ITER_END : OB_SUCCESS; } } else { col_node.curr_ = t_val; ret = ctx->is_need_end_ ? OB_ITER_END : OB_SUCCESS; } } else if (col_type == COL_TYPE_EXISTS) { int is_true = 0; if (info.on_error_ == JSN_EXIST_ERROR) { ret = ctx->error_code_; if (OB_SUCC(ret) && ctx->is_need_end_) { ret = OB_ITER_END; } } else if (info.on_error_ == JSN_EXIST_DEFAULT || info.on_error_ == JSN_EXIST_FALSE) { is_null = false; ret = ctx->is_need_end_ ? OB_ITER_END : OB_SUCCESS; } else if (info.on_error_ == JSN_EXIST_TRUE) { is_true = 0; is_null = false; ret = ctx->is_need_end_ ? OB_ITER_END : OB_SUCCESS; } if (OB_FAIL(ret)) { } else if (ob_is_string_type(info.data_type_.get_obj_type())) { ObString value = is_true ? ObString("true") : ObString("false"); if (lib::is_mysql_mode()) { value = is_true ? ObString("1") : ObString("0"); } void* buf = ctx->row_alloc_.alloc(sizeof(ObJsonString)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret)); } else { col_node.curr_ = static_cast(new(buf)ObJsonString(value.ptr(), value.length())); is_null = false; } } else if (ob_is_number_tc(info.data_type_.get_obj_type()) || lib::is_mysql_mode()) { void* buf = ctx->row_alloc_.alloc(sizeof(ObJsonInt)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret)); } else { col_node.curr_ = static_cast(new(buf)ObJsonInt(is_true)); is_null = false; } } else { if (col_node.col_info_.on_error_ != JSN_EXIST_ERROR) { col_node.curr_ = nullptr; is_null = true; } else { ret = OB_ERR_NON_NUMERIC_CHARACTER_VALUE; } } } if (OB_SUCC(ret) && is_null) { expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); } } return ret; } int JsonTableFunc::cast_to_result(ObRegCol& col_node, JtScanCtx* ctx, bool enable_error, bool is_pack_result) { INIT_SUCC(ret); ObIJsonBase *js_val = static_cast(col_node.curr_); ObJtColInfo& col_info = col_node.get_column_def(); bool is_truncate = static_cast(col_info.truncate_); JtColType col_type = col_node.type(); ObExpr* expr = ctx->spec_ptr_->column_exprs_.at(col_info.output_column_idx_); ObDatum& res = expr->locate_datum_for_write(*ctx->eval_ctx_); ctx->res_obj_ = &res; uint8_t is_type_mismatch = false; uint8_t ascii_type = false; ObObjType dst_type = expr->datum_meta_.type_; ObCollationType coll_type = expr->datum_meta_.cs_type_; ObAccuracy accuracy = col_info.data_type_.get_accuracy(); ObCollationType dst_coll_type = col_info.data_type_.get_collation_type(); ObCollationType in_coll_type = ctx->is_charset_converted_ ? CS_TYPE_UTF8MB4_BIN : ctx->spec_ptr_->value_expr_->datum_meta_.cs_type_; ObCollationLevel dst_coll_level = col_info.data_type_.get_collation_level(); bool is_quote = (col_info.col_type_ == COL_TYPE_QUERY && js_val->json_type() == ObJsonNodeType::J_STRING); ObJsonCastParam cast_param(dst_type, in_coll_type, dst_coll_type, ascii_type); cast_param.is_const_ = ctx->is_const_input_; cast_param.is_trunc_ = is_truncate; cast_param.is_json_table_ = true; cast_param.rt_expr_ = expr; switch (col_type) { case JtColType::COL_TYPE_VALUE: { if (col_node.res_flag_ != ResultType::NOT_DATUM) { ObDatum *js_val = static_cast(col_node.curr_); ObExpr* default_expr; if (col_node.res_flag_ == ResultType::EMPTY_DATUM) { default_expr = ctx->spec_ptr_->emp_default_exprs_.at(col_node.col_info_.empty_expr_id_); } else if (col_node.res_flag_ == ResultType::ERROR_DATUM) { default_expr = ctx->spec_ptr_->err_default_exprs_.at(col_node.col_info_.error_expr_id_); } if (OB_ISNULL(js_val)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("empty/error value can not be null", K(ret)); } else if (OB_FAIL(ObJsonExprHelper::cast_to_res(ctx->row_alloc_, *js_val, *expr, *default_expr, *ctx->eval_ctx_, res, true))) { enable_error = false; LOG_WARN("fail to cast to res", K(ret)); } } else { ret = ObJsonUtil::cast_to_res(&ctx->row_alloc_, *ctx->eval_ctx_, js_val, accuracy, cast_param, res, is_type_mismatch); } break; } case JtColType::COL_TYPE_QUERY: { cast_param.is_quote_ = true; ret = ObJsonUtil::cast_to_res(&ctx->row_alloc_, *ctx->eval_ctx_, js_val, accuracy, cast_param, res, is_type_mismatch); break; } case JtColType::COL_TYPE_EXISTS: { ret = ObJsonUtil::cast_to_res(&ctx->row_alloc_, *ctx->eval_ctx_, js_val, accuracy, cast_param, res, is_type_mismatch); break; } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect type input", K(ret)); break; } } if (OB_FAIL(ret) && enable_error) { int tmp_ret = set_on_error(col_node, ctx, ret); if (tmp_ret != OB_SUCCESS) { LOG_WARN("failed to set error val.", K(tmp_ret)); } else if (OB_SUCC(tmp_ret) && OB_NOT_NULL(col_node.curr_) && OB_FAIL(cast_to_result(col_node, ctx, false, false))) { // due of without type calc, so use cast transform default value to res. LOG_WARN("fail to cast default value to res", K(ret)); } } if (OB_SUCC(ret) && is_pack_result && is_lob_storage(dst_type) && (col_node.res_flag_ == ResultType::NOT_DATUM) && !res.is_null()) { ObString val = res.get_string(); if (OB_FAIL(ObJsonExprHelper::pack_json_str_res(*expr, *ctx->eval_ctx_, res, val, &ctx->row_alloc_))) { LOG_WARN("fail to pack res result.", K(ret)); } } return ret; } int JsonTableFunc::eval_seek_col(ObRegCol &col_node, void* in, JtScanCtx* ctx, bool &is_null_value, bool &need_cast_res) { INIT_SUCC(ret); ObJsonSeekResult hit; ObIJsonBase* in_val = static_cast(in); ObJsonPath* json_path = static_cast(col_node.path_); ObExpr* col_expr = ctx->spec_ptr_->column_exprs_.at(col_node.col_info_.output_column_idx_); in_val->set_allocator(&ctx->row_alloc_); if (OB_FAIL(in_val->seek(*json_path, json_path->path_node_cnt(), true, false, hit))) { SET_COVER_ERROR(ctx, ret); LOG_WARN("json seek failed", K(col_node.col_info_.path_), K(ret)); } else if (hit.size() == 0) { col_node.curr_ = nullptr; is_null_value = true; } else if (col_node.type() == COL_TYPE_EXISTS && hit.size() > 0) { is_null_value = false; col_node.curr_ = hit[0]; } else if (col_node.type() != COL_TYPE_QUERY && hit.size() == 1) { is_null_value = false; col_node.curr_ = hit[0]; } else if (col_node.type() == COL_TYPE_VALUE && !(lib::is_mysql_mode() && ob_is_json(col_expr->datum_meta_.type_))) { ret = OB_ERR_JSON_VALUE_NO_SCALAR; SET_COVER_ERROR(ctx, ret); } else if (col_node.type() == COL_TYPE_QUERY || (col_node.type() == COL_TYPE_VALUE && lib::is_mysql_mode() && ob_is_json(col_expr->datum_meta_.type_))) { void* js_arr_buf = ctx->row_alloc_.alloc(sizeof(ObJsonArray)); ObIJsonBase* js_arr_ptr = nullptr; if (OB_ISNULL(js_arr_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate json array buf", K(ret)); } else if (OB_ISNULL(js_arr_ptr = new (js_arr_buf) ObJsonArray(&ctx->row_alloc_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to new json array node", K(ret)); } else if (OB_FAIL(ObExprJsonQuery::append_node_into_res(js_arr_ptr, json_path, hit, &ctx->row_alloc_))) { LOG_WARN("fail to tree apeend node", K(ret)); } if (OB_SUCC(ret)) { is_null_value = false; col_node.curr_ = js_arr_ptr; } } return ret; } int JsonTableFunc::init_ctx(ObRegCol &scan_node, JtScanCtx*& ctx) { INIT_SUCC(ret); ObJsonPath* js_path = NULL; scan_node.tab_type_ = MulModeTableType::OB_ORA_JSON_TABLE_TYPE; bool need_eval = false; // flag of eval default value bool need_datum = lib::is_oracle_mode(); if (!scan_node.is_path_evaled_ && OB_ISNULL(scan_node.path_) && (scan_node.node_type() == REG_TYPE || scan_node.node_type() == SCAN_TYPE) && !scan_node.col_info_.path_.empty()) { void* path_buf = ctx->op_exec_alloc_->alloc(sizeof(ObJsonPath)); if (OB_ISNULL(path_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate json path buffer", K(ret)); } else { js_path = new (path_buf) ObJsonPath(scan_node.col_info_.path_, ctx->op_exec_alloc_); if (OB_FAIL(js_path->parse_path())) { ret = OB_ERR_JSON_PATH_EXPRESSION_SYNTAX_ERROR; LOG_USER_ERROR(OB_ERR_JSON_PATH_EXPRESSION_SYNTAX_ERROR, scan_node.col_info_.path_.length(), scan_node.col_info_.path_.ptr()); } else { scan_node.expr_param_.json_path_ = js_path; scan_node.path_ = js_path; scan_node.is_path_evaled_ = true; } } } if (OB_FAIL(ret)) { } else if (scan_node.node_type() == REG_TYPE) { if (!scan_node.is_emp_evaled_) { need_eval = false; if (scan_node.type() == COL_TYPE_VALUE) { if (scan_node.col_info_.on_empty_ == JSN_VALUE_IMPLICIT && scan_node.col_info_.on_error_ == JSN_VALUE_DEFAULT) { ObExpr* default_expr = ctx->spec_ptr_->err_default_exprs_.at(scan_node.col_info_.error_expr_id_); if (OB_FAIL(eval_default_value(ctx, default_expr, scan_node.err_val_, need_datum))) { ret = OB_INVALID_DEFAULT; LOG_USER_ERROR(OB_INVALID_DEFAULT, scan_node.col_info_.col_name_.length(), scan_node.col_info_.col_name_.ptr()); } else { scan_node.is_err_evaled_ = true; } } else if (scan_node.col_info_.on_empty_ == JSN_VALUE_DEFAULT) { ObExpr* default_expr = ctx->spec_ptr_->emp_default_exprs_.at(scan_node.col_info_.empty_expr_id_); if (OB_FAIL(eval_default_value(ctx, default_expr, scan_node.emp_val_, need_datum))) { ret = OB_INVALID_DEFAULT; LOG_USER_ERROR(OB_INVALID_DEFAULT, scan_node.col_info_.col_name_.length(), scan_node.col_info_.col_name_.ptr()); } else { scan_node.is_emp_evaled_ = true; } } } } if (OB_SUCC(ret) && !scan_node.is_err_evaled_) { need_eval = false; if (scan_node.type() == COL_TYPE_VALUE) { if (scan_node.col_info_.on_error_ == JSN_VALUE_DEFAULT) { need_eval = true; } if (need_eval) { ObExpr* default_expr = ctx->spec_ptr_->err_default_exprs_.at(scan_node.col_info_.error_expr_id_); if (OB_FAIL(eval_default_value(ctx, default_expr, scan_node.err_val_, need_datum))) { ret = OB_INVALID_DEFAULT; LOG_USER_ERROR(OB_INVALID_DEFAULT, scan_node.col_info_.col_name_.length(), scan_node.col_info_.col_name_.ptr()); } else { scan_node.is_err_evaled_ = true; } } } } scan_node.res_flag_ = ResultType::NOT_DATUM; ObExpr* col_expr = ctx->spec_ptr_->column_exprs_.at(scan_node.col_info_.output_column_idx_); if (OB_FAIL(ret)) { } else if (OB_FAIL(set_expr_exec_param(scan_node, ctx))) { LOG_WARN("fail to init expr param", K(ret)); } else if (OB_FAIL(RegularCol::check_item_method_json(scan_node, ctx))) { LOG_WARN("fail to check expr param", K(ret)); } else if (OB_FAIL(check_default_value(ctx, scan_node, col_expr))) { // json value empty need check default value first LOG_WARN("default value check fail", K(ret)); } } return ret; } int JsonTableFunc::eval_default_value(JtScanCtx*& ctx, ObExpr*& default_expr, void*& res, bool need_datum) { INIT_SUCC(ret); ObDatum* emp_datum = nullptr; ObIJsonBase* emp_json = nullptr; if (OB_FAIL(default_expr->eval(*ctx->eval_ctx_, emp_datum))) { LOG_WARN("failed do cast to returning type.", K(ret)); } else if (need_datum) { res = emp_datum; } else if (OB_FAIL(RegularCol::parse_default_value_2json(default_expr, ctx, emp_datum, emp_json))) { LOG_WARN("fail to process empty default value", K(ret)); } else { res = emp_json; } return ret; } int JsonTableFunc::reset_path_iter(ObRegCol &scan_node, void* in, JtScanCtx*& ctx, ScanType init_flag, bool &is_null_value) { INIT_SUCC(ret); if (init_flag == SCAN_NODE_TYPE) { ObJsonSeekResult hit; ObIJsonBase* in_val = static_cast(in); ObJsonPath* js_path = static_cast(scan_node.path_); in_val->set_allocator(&ctx->row_alloc_); if (OB_ISNULL(in_val) || OB_ISNULL(js_path)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpect input", K(ret)); } else if (OB_FAIL(in_val->seek(*js_path, js_path->path_node_cnt(), true, false, hit))) { LOG_WARN("json seek failed", K(js_path), K(ret)); SET_COVER_ERROR(ctx, ret); } else if (hit.size() == 0) { scan_node.cur_pos_ = 0; scan_node.total_ = 1; is_null_value = true; scan_node.curr_ = scan_node.iter_ = nullptr; } else if (hit.size() == 1) { scan_node.iter_ = scan_node.curr_ = hit[0]; is_null_value = false; scan_node.cur_pos_ = 0; scan_node.total_ = 1; } else { is_null_value = false; void* js_arr_buf = ctx->row_alloc_.alloc(sizeof(ObJsonArray)); ObJsonArray* js_arr_ptr = nullptr; if (OB_ISNULL(js_arr_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate json array buf", K(ret)); } else if (OB_ISNULL(js_arr_ptr = new (js_arr_buf) ObJsonArray(&ctx->row_alloc_))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to new json array node", K(ret)); } else { ObJsonNode *j_node = NULL; ObIJsonBase *jb_node = NULL; for (int32_t i = 0; OB_SUCC(ret) && i < hit.size(); i++) { if (ObJsonBaseFactory::transform(&ctx->row_alloc_, hit[i], ObJsonInType::JSON_TREE, jb_node)) { // to tree LOG_WARN("fail to transform to tree", K(ret), K(i), K(*(hit[i]))); } else { j_node = static_cast(jb_node); if (OB_FAIL(js_arr_ptr->array_append(j_node->clone(&ctx->row_alloc_)))) { LOG_WARN("failed to array append", K(ret), K(i), K(*j_node)); } } } if (OB_SUCC(ret)) { scan_node.curr_ = js_arr_ptr; scan_node.total_ = hit.size(); ObIJsonBase* iter = NULL; if (OB_FAIL(js_arr_ptr->get_array_element(0, iter))) { LOG_WARN("failed to get array selement 0.", K(ret)); } else { scan_node.iter_ = iter; } } } } } else { // do nothing in col node } return ret; } int JsonTableFunc::get_iter_value(ObRegCol &col_node, JtScanCtx* ctx, bool &is_null_value) { INIT_SUCC(ret); if (col_node.cur_pos_ + 1 < col_node.total_) { col_node.cur_pos_++; if (OB_FAIL(container_at(col_node.curr_, col_node.iter_, col_node.cur_pos_))) { LOG_WARN("fail to get container element.", K(ret), K(col_node.cur_pos_)); } } else { ret = OB_ITER_END; } return ret; } int JsonTableFunc::eval_input(ObJsonTableOp &jt, JtScanCtx& ctx, ObEvalCtx &eval_ctx) { INIT_SUCC(ret); common::ObObjMeta& doc_obj_datum = ctx.spec_ptr_->value_expr_->obj_meta_; ObDatumMeta& doc_datum = ctx.spec_ptr_->value_expr_->datum_meta_; ObObjType doc_type = doc_datum.type_; ObCollationType doc_cs_type = doc_datum.cs_type_; ObString j_str; bool is_null = false; ObIJsonBase* in = NULL; if (doc_type == ObNullType) { ret = OB_ITER_END; } else if (doc_type == ObNCharType || !(doc_type == ObJsonType || doc_type == ObRawType || ob_is_string_type(doc_type))) { ret = OB_ERR_INPUT_JSON_TABLE; LOG_WARN("fail to get json base", K(ret), K(doc_type)); } else { jt.reset_columns(); if (OB_FAIL(ObJsonExprHelper::get_json_or_str_data(ctx.spec_ptr_->value_expr_, eval_ctx, ctx.row_alloc_, j_str, is_null))) { ret = OB_ERR_INPUT_JSON_TABLE; LOG_WARN("get real data failed", K(ret)); } else if (is_null) { ret = OB_ITER_END; } else if ((ob_is_string_type(doc_type) || doc_type == ObLobType) && (doc_cs_type != CS_TYPE_BINARY) && (ObCharset::charset_type_by_coll(doc_cs_type) != CHARSET_UTF8MB4)) { // need convert to utf8 first, we are using GenericInsituStringStream > char *buf = nullptr; const int64_t factor = 2; int64_t buf_len = j_str.length() * factor; uint32_t result_len = 0; if (OB_ISNULL(buf = static_cast(ctx.row_alloc_.alloc(buf_len)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc memory failed", K(ret)); } else if (OB_FAIL(ObCharset::charset_convert(doc_cs_type, j_str.ptr(), j_str.length(), CS_TYPE_UTF8MB4_BIN, buf, buf_len, result_len))) { LOG_WARN("charset convert failed", K(ret)); } else { ctx.is_charset_converted_ = true; j_str.assign_ptr(buf, result_len); } } ObJsonInType j_in_type = ObJsonExprHelper::get_json_internal_type(doc_type); ObJsonInType expect_type = ObJsonInType::JSON_TREE; uint32_t parse_flag = lib::is_oracle_mode() ? ObJsonParser::JSN_RELAXED_FLAG : ObJsonParser::JSN_DEFAULT_FLAG; // json type input, or has is json check bool is_ensure_json = lib::is_oracle_mode() && (doc_type != ObJsonType); if (OB_FAIL(ret)) { } else if (OB_FAIL(ObJsonBaseFactory::get_json_base(&ctx.row_alloc_, j_str, j_in_type, expect_type, in, parse_flag)) || (in->json_type() != ObJsonNodeType::J_ARRAY && in->json_type() != ObJsonNodeType::J_OBJECT)) { if (OB_FAIL(ret) || (is_ensure_json)) { in= nullptr; ret = OB_ERR_JSON_SYNTAX_ERROR; SET_COVER_ERROR(&ctx, ret); ctx.is_need_end_ = 1; if (lib::is_oracle_mode() && jt.get_root_entry()->get_scan_node()->seek_node_.col_info_.on_error_ != JSN_QUERY_ERROR) { ret = OB_SUCCESS; } } else { ret = OB_SUCCESS; } } if (OB_SUCC(ret)) { jt.input_ = in; } } return ret; } int JsonTableFunc::container_at(void* in, void *&out, int32_t pos) { INIT_SUCC(ret); ObIJsonBase* in_ = static_cast(in); ObIJsonBase* res = nullptr; if (in_->json_type() == ObJsonNodeType::J_ARRAY) { if (OB_FAIL(in_->get_array_element(pos, res))) { LOG_WARN("fail to get array element", K(ret), K(pos)); } } else if (in_->json_type() == ObJsonNodeType::J_OBJECT) { if (OB_FAIL(in_->get_object_value(pos, res))) { LOG_WARN("fail to get object element", K(ret), K(pos)); } } if (OB_SUCC(ret)) { out = res; } return ret; } } // end namespace sql } // end namespace oceanbase