diff --git a/deps/oblib/src/lib/CMakeLists.txt b/deps/oblib/src/lib/CMakeLists.txt index 5d8f6ab32..a89ba4232 100644 --- a/deps/oblib/src/lib/CMakeLists.txt +++ b/deps/oblib/src/lib/CMakeLists.txt @@ -249,6 +249,7 @@ ob_set_subtarget(oblib_lib common_mixed xml/ob_binary_aggregate.cpp locale/ob_locale_type.cc locale/ob_locale.cpp + enumset/ob_enum_set_meta.cpp ) ob_set_subtarget(oblib_lib lock diff --git a/deps/oblib/src/lib/enumset/ob_enum_set_meta.cpp b/deps/oblib/src/lib/enumset/ob_enum_set_meta.cpp new file mode 100644 index 000000000..2675cba4f --- /dev/null +++ b/deps/oblib/src/lib/enumset/ob_enum_set_meta.cpp @@ -0,0 +1,179 @@ +/** + * 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 LIB +#include "ob_enum_set_meta.h" +#include "lib/container/ob_array_helper.h" +#include "share/ob_define.h" + + +namespace oceanbase { +namespace common { + +bool ObEnumSetMeta::is_same(const ObObjMeta &obj_meta, const ObStrValues &str_value) const +{ + bool is_same_meta = true; + if (OB_LIKELY(!is_valid())) { + is_same_meta = false; + } else if (obj_meta != obj_meta_) { + is_same_meta = false; + } else if (str_value.count() != str_values_->count()) { + is_same_meta = false; + } else { + for (int64_t i = 0; is_same_meta && i < str_value.count(); ++i) { + const ObString &str1 = str_value.at(i); + const ObString &str2 = str_values_->at(i); + if (str1.length() != str2.length()) { + is_same_meta = false; + } else { + is_same_meta = (0 == MEMCMP(str1.ptr(), str2.ptr(), str1.length())); + } + } + } + return is_same_meta; +} + +bool ObEnumSetMeta::is_same(const ObEnumSetMeta &other) const +{ + bool is_same_meta = true; + if (this == &other) { + is_same_meta = true; + } else if (other.is_valid()) { + is_same_meta = is_same(other.get_obj_meta(), *other.get_str_values()); + } + return is_same_meta; +} + +uint64_t ObEnumSetMeta::hash() const +{ + uint64_t hash_val = 0; + if (is_valid()) { + const uint64_t subschema_id = obj_meta_.get_subschema_id(); + hash_val = obj_meta_.is_set() ? subschema_id : ~subschema_id; + for (int64_t i = 0; i < str_values_->count(); ++i) { + hash_val = str_values_->at(i).hash(hash_val); + } + } + return hash_val; +} + +int ObEnumSetMeta::deep_copy(ObIAllocator &allocator, ObEnumSetMeta *&dst) const +{ + int ret = OB_SUCCESS; + void *mem = NULL; + const int64_t mem_size = sizeof(ObEnumSetMeta) + sizeof(ObFixedArray); + ObEnumSetMeta *meta = NULL; + ObFixedArray *str_values = NULL; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("src meta is invalid", K(ret), KPC(this)); + } else if (OB_ISNULL(mem = allocator.alloc(mem_size))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc udt meta", K(ret), K(mem_size)); + } else { + meta = new(mem)ObEnumSetMeta(); + void *array_ptr = static_cast(mem) + sizeof(ObEnumSetMeta); + str_values = new(array_ptr) ObFixedArray(allocator); + if (OB_FAIL(str_values->init(str_values_->count()))) { + LOG_WARN("fail to init array", K(ret)); + } else { + // deep copy string + for (int64_t i = 0; OB_SUCC(ret) && i < str_values_->count(); ++i) { + ObString dst_str; + if (OB_FAIL(ob_write_string(allocator, str_values_->at(i), dst_str))) { + LOG_WARN("fail to deep copying string", K(ret)); + } else if (OB_FAIL(str_values->push_back(dst_str))) { + LOG_WARN("push_back failed", K(ret)); + // free memory avoid memory leak + for (int64_t j = 0; j < str_values->count(); ++j) { + allocator.free(str_values->at(j).ptr()); + } + allocator.free(dst_str.ptr()); + } + } + } + if (OB_FAIL(ret)) { + allocator.free(mem); + mem = NULL; + } else { + meta->obj_meta_.set_meta(obj_meta_); + meta->str_values_ = str_values; + dst = meta; + } + } + return ret; +} + +static_assert(ObEnumSetMeta::MetaState::UNINITIALIZED == SCALE_UNKNOWN_YET, + "make sure the value of uninitialized state always be equal to scale unkown yet"); + +OB_DEF_SERIALIZE(ObEnumSetMeta) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("src meta is invalid", K(ret), KPC(this)); + } else { + OB_UNIS_ENCODE(obj_meta_); + OB_UNIS_ENCODE_ARRAY(str_values_->get_data(), str_values_->count()); + } + return ret; +} + +OB_DEF_DESERIALIZE(ObEnumSetMeta) +{ + int ret = OB_SUCCESS; + int64_t count = 0; + OB_UNIS_DECODE(obj_meta_); + OB_UNIS_DECODE(count); + const int64_t array_size = sizeof(ObArrayHelper); // for array container + const int64_t strings_size = count * sizeof(ObString); // for string data + void *mem = NULL; + if (OB_ISNULL(allocator_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("allocator is need for deserialize", K(ret), K(lbt())); + } else if (OB_UNLIKELY(0 == count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("string values count is zero", K(ret)); + } else if (OB_ISNULL(mem = allocator_->alloc(strings_size + array_size))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate mem", K(ret), K(strings_size), K(array_size)); + } else if (FALSE_IT(MEMSET(mem, 0, strings_size + array_size))) { + } else { + ObArrayHelper *array_helper = new(mem)(ObArrayHelper); + ObString *strings = reinterpret_cast(static_cast(mem) + array_size); + OB_UNIS_DECODE_ARRAY(strings, count); + if (OB_SUCC(ret)) { + array_helper->init(count, strings, count); + str_values_ = array_helper; + } + } + if (OB_FAIL(ret) && OB_NOT_NULL(mem)) { + allocator_->free(mem); + str_values_ = NULL; + mem = NULL; + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObEnumSetMeta) +{ + int64_t len = 0; + if (is_valid()) { + OB_UNIS_ADD_LEN(obj_meta_); + OB_UNIS_ADD_LEN_ARRAY(str_values_->get_data(), str_values_->count()); + } + return len; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/enumset/ob_enum_set_meta.h b/deps/oblib/src/lib/enumset/ob_enum_set_meta.h new file mode 100644 index 000000000..ef8adc949 --- /dev/null +++ b/deps/oblib/src/lib/enumset/ob_enum_set_meta.h @@ -0,0 +1,102 @@ +/** + * 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_OB_ENUM_SET_EMTA_TYPE_ +#define OCEANBASE_OB_ENUM_SET_EMTA_TYPE_ + +#include +#include +#include "common/object/ob_object.h" +#include "lib/container/ob_array_helper.h" +#include "lib/string/ob_string.h" +#include "share/ob_cluster_version.h" + +namespace oceanbase { +namespace common { + +/** + * The struct ObEnumSetMeta is primarily used to store complex meta-information about + * `enum` and `set` types. It contains `obj_meta` to save `cs_type` and array `str_values` that + * encapsulates the set of string representations associated with the enumerated type values. + * It is intended to be stored within `ObSubSchemaCtx` and is utilized during the execution phase + * to retrieve the extended type info about enum/set type. + */ +struct ObEnumSetMeta +{ + OB_UNIS_VERSION(1); + +private: + typedef ObIArray ObStrValues; + +public: + /** + * Since the `scale` field within the `ObExprResType` of the enum/set type is not used, we use + * this field to save the meta state. + */ + enum MetaState + { + UNINITIALIZED = -1, // meta has not been saved, -1(SCALE_UNKNOWN_YET) as the default value + SKIP = 0, // used in pl, compilation and running are separated, so skip this scenario + READY = 1, // meta has been saved in `ObSubSchemaCtx` + MAX_STATE + }; + +public: + ObEnumSetMeta(common::ObIAllocator *alloc = NULL) : obj_meta_(), str_values_(NULL), + allocator_(alloc) {} + ObEnumSetMeta(ObObjMeta obj_meta, const ObStrValues *str_value) : + obj_meta_(obj_meta), str_values_(str_value), allocator_(NULL) {} + inline bool is_valid() const + { + return obj_meta_.is_enum_or_set() && NULL != str_values_ && !str_values_->empty(); + } + bool is_same(const ObObjMeta &obj_meta, const ObStrValues &str_value) const; + bool is_same(const ObEnumSetMeta &other) const; + uint64_t hash() const; + int hash(uint64_t &res) const + { + res = hash(); + return common::OB_SUCCESS; + } + inline bool operator ==(const ObEnumSetMeta &other) const { return is_same(other); } + inline bool operator !=(const ObEnumSetMeta &other) const { return !this->operator==(other); } + int deep_copy(ObIAllocator &allocator, ObEnumSetMeta *&dst) const; + void destroy() + { + if (OB_NOT_NULL(allocator_) && OB_NOT_NULL(str_values_)) { + allocator_->free(const_cast(str_values_)); + allocator_ = NULL; + } + } + inline uint64_t get_signature() const { return udt_id_; } + inline const common::ObObjMeta &get_obj_meta() const { return obj_meta_; } + inline ObObjType get_type() const { return obj_meta_.get_type(); } + inline ObCollationType get_collation_type() const { return obj_meta_.get_collation_type(); } + inline ObCollationLevel get_collation_level() const { return obj_meta_.get_collation_level(); } + inline const ObStrValues *get_str_values() const { return str_values_; } + + TO_STRING_KV(K_(obj_meta), KP_(str_values), KP_(allocator)); + +private: + common::ObObjMeta obj_meta_; // original type obj meta + union + { + const ObStrValues *str_values_; // pointer to extended type info + uint64_t udt_id_; + }; + common::ObIAllocator *allocator_; // used for deserialize only +}; + + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_OB_ENUM_SET_EMTA_TYPE_ diff --git a/deps/oblib/src/lib/rc/context.cpp b/deps/oblib/src/lib/rc/context.cpp index ddf09b8b8..c21aeb28e 100644 --- a/deps/oblib/src/lib/rc/context.cpp +++ b/deps/oblib/src/lib/rc/context.cpp @@ -56,5 +56,14 @@ MemoryContext &MemoryContext::root() return root; } +int64_t MemoryContext::tree_mem_hold() +{ + int64_t total = 0; + if (OB_LIKELY(ref_context_ != nullptr)) { + total = ref_context_->tree_mem_hold(); + } + return total; +} + } // end of namespace lib } // end of namespace oceanbase diff --git a/deps/oblib/src/lib/rc/context.h b/deps/oblib/src/lib/rc/context.h index 294737253..db055191d 100644 --- a/deps/oblib/src/lib/rc/context.h +++ b/deps/oblib/src/lib/rc/context.h @@ -67,7 +67,6 @@ namespace lib CONTEXT_P(condition, lib::ContextSource::CREATE, \ lib::DynamicInfo(), __VA_ARGS__, &static_info) - using std::nullptr_t; using lib::ObMemAttr; class Flow; @@ -286,6 +285,7 @@ public: __MemoryContext__ *ref_context() const { return ref_context_; } bool check_magic_code() const { return MAGIC_CODE == magic_code_; } + int64_t tree_mem_hold(); static MemoryContext &root(); private: int64_t magic_code_; @@ -606,6 +606,20 @@ public: destory_context(ref_context); } } + int64_t tree_mem_hold() + { + int64_t total = 0; + if (!tree_node_.with_lock_) { + TreeNode *child_node = tree_node_.child_; + while (child_node != nullptr) { + __MemoryContext__ *child = node2context(child_node); + total += child->tree_mem_hold(); + child_node = child_node->next_; + } + total += hold(); + } + return total; + } public: int64_t magic_code_; int64_t seq_id_; diff --git a/deps/oblib/src/lib/udt/ob_collection_type.h b/deps/oblib/src/lib/udt/ob_collection_type.h index 70153a081..905d16d56 100644 --- a/deps/oblib/src/lib/udt/ob_collection_type.h +++ b/deps/oblib/src/lib/udt/ob_collection_type.h @@ -75,6 +75,8 @@ public: ObSqlCollectionInfo(ObIAllocator &allocator) : allocator_(allocator), name_len_(0), name_def_(nullptr), collection_meta_(nullptr) {} + ObSqlCollectionInfo(common::ObIAllocator *allocator) + : ObSqlCollectionInfo(*allocator) {} virtual ~ObSqlCollectionInfo() {} void set_name(ObString &name) { @@ -89,6 +91,7 @@ public: } ObString get_def_string() const {return ObString(name_len_, name_def_);} + int64_t get_signature() const { return get_def_string().hash(); } int get_child_def_string(ObString &child_def) const; int deep_copy(ObIAllocator &allocator, ObSqlCollectionInfo *&dst) const; int create_meta_info_by_name(const std::string &name, ObCollectionTypeBase *&meta_info, uint8_t &arr_depth); diff --git a/deps/oblib/src/lib/udt/ob_udt_type.h b/deps/oblib/src/lib/udt/ob_udt_type.h index c69f45671..afd5bba73 100644 --- a/deps/oblib/src/lib/udt/ob_udt_type.h +++ b/deps/oblib/src/lib/udt/ob_udt_type.h @@ -65,6 +65,10 @@ typedef struct ObSqlUDTMeta { OB_UNIS_VERSION(1); public: + ObSqlUDTMeta(common::ObIAllocator *alloc = NULL) + { + reset(); + } void set_name(ObString &name) { udt_name_ = name.ptr(); @@ -114,6 +118,7 @@ public: int deep_copy(ObIAllocator &allocator, ObSqlUDTMeta *&dst) const; + inline uint64_t get_signature() const { return udt_id_; } TO_STRING_KV(K_(attribute_cnt), K_(fixed_attr_cnt), K_(fixed_offset), diff --git a/src/objit/include/objit/expr/ob_iraw_expr.h b/src/objit/include/objit/expr/ob_iraw_expr.h index d16f727f4..daa7637a6 100644 --- a/src/objit/include/objit/expr/ob_iraw_expr.h +++ b/src/objit/include/objit/expr/ob_iraw_expr.h @@ -151,6 +151,7 @@ public: void set_collation_level(common::ObCollationLevel cs_level); void set_collation_type(common::ObCollationType cs_type); void set_accuracy(const common::ObAccuracy &accuracy); + void set_collation(const common::ObObjMeta &meta_type); void set_result_flag(const uint32_t flag); void set_scale(const int16_t scale); void set_precision(const int16_t precision); @@ -163,6 +164,12 @@ public: virtual int64_t get_children_count() const; virtual int get_children(ExprArray &jit_exprs) const; + // used for record meta state for enum/set types + void mark_enum_set_with_subschema(); + void mark_enum_set_skip_build_subschema(); + void reset_enum_set_meta_state(); + bool is_enum_set_with_subschema() const; + bool skip_build_subschema_for_enumset() const; TO_STRING_KV(K_(type), K_(expr_class)); @@ -275,6 +282,10 @@ inline void ObIRawExpr::set_accuracy(const common::ObAccuracy &accuracy) { result_type_.set_accuracy(accuracy); } +inline void ObIRawExpr::set_collation(const common::ObObjMeta &meta_type) +{ + result_type_.set_collation(meta_type); +} inline void ObIRawExpr::set_result_flag(const uint32_t flag) { result_type_.set_result_flag(flag); @@ -327,6 +338,29 @@ inline int ObIRawExpr::accept(Visitor __attribute__ ((unused)) &v) const return common::OB_NOT_SUPPORTED; } +inline void ObIRawExpr::mark_enum_set_with_subschema() +{ + result_type_.mark_enum_set_with_subschema(); +} + +inline void ObIRawExpr::mark_enum_set_skip_build_subschema() +{ + result_type_.set_scale(ObEnumSetMeta::MetaState::SKIP); +} + +inline void ObIRawExpr::reset_enum_set_meta_state() { result_type_.reset_enum_set_meta_state(); } + +inline bool ObIRawExpr::is_enum_set_with_subschema() const +{ + return result_type_.is_enum_set_with_subschema(); +} + +inline bool ObIRawExpr::skip_build_subschema_for_enumset() const +{ + return result_type_.get_scale() == ObEnumSetMeta::MetaState::SKIP || + result_type_.get_scale() == ObEnumSetMeta::MetaState::READY; +} + } // expr } // jit } // oceanbase diff --git a/src/observer/ob_inner_sql_connection.cpp b/src/observer/ob_inner_sql_connection.cpp index 91827c352..fa642ec6b 100644 --- a/src/observer/ob_inner_sql_connection.cpp +++ b/src/observer/ob_inner_sql_connection.cpp @@ -682,6 +682,8 @@ int ObInnerSQLConnection::do_query(sqlclient::ObIExecutor &executor, ObInnerSQLR { int ret = OB_SUCCESS; WITH_CONTEXT(res.mem_context_) { + // are there no restrictions on internal SQL such as refresh schema? + // MEM_TRACKER_GUARD(CURRENT_CONTEXT); // restore有自己的inner_sql_connection,sql_modifier不为null bool is_restore = NULL != sql_modifier_; res.sql_ctx().is_restore_ = is_restore; diff --git a/src/observer/ob_rpc_processor_simple.cpp b/src/observer/ob_rpc_processor_simple.cpp index 60a8e1e41..ef8ef4eb5 100644 --- a/src/observer/ob_rpc_processor_simple.cpp +++ b/src/observer/ob_rpc_processor_simple.cpp @@ -2708,8 +2708,8 @@ int ObCleanSequenceCacheP::process() if (OB_ISNULL(GCTX.schema_service_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("schema service is null", K(ret)); - } else if (OB_FAIL(sequence_cache.remove(MTL_ID(), sequence_id))) { - LOG_WARN("remove sequence item from sequence cache failed", K(ret), K(sequence_id)); + } else if (OB_FAIL(sequence_cache.remove(MTL_ID(), sequence_id, result_))) { + LOG_WARN("remove sequence item from sequence cache failed", K(ret), K(sequence_id), K(result_)); } return ret; } diff --git a/src/observer/omt/ob_th_worker.cpp b/src/observer/omt/ob_th_worker.cpp index 00dd2b16b..7fe872b76 100644 --- a/src/observer/omt/ob_th_worker.cpp +++ b/src/observer/omt/ob_th_worker.cpp @@ -30,6 +30,7 @@ #include "observer/ob_server.h" #include "storage/memtable/ob_lock_wait_mgr.h" #include "sql/session/ob_sql_session_info.h" +#include "sql/executor/ob_memory_tracker.h" using namespace oceanbase; using namespace oceanbase::lib; @@ -350,6 +351,7 @@ void ObThWorker::worker(int64_t &tenant_id, int64_t &req_recv_timestamp, int32_t .set_properties(lib::USE_TL_PAGE_OPTIONAL) .set_ablock_size(lib::INTACT_MIDDLE_AOBJECT_SIZE); CREATE_WITH_TEMP_CONTEXT(param) { + MEM_TRACKER_GUARD(CURRENT_CONTEXT); const uint64_t owner_id = (!is_virtual_tenant_id(tenant_->id()) || is_virtual_tenant_for_memory(tenant_->id())) ? tenant_->id() : OB_SERVER_TENANT_ID; @@ -473,7 +475,8 @@ int ObThWorker::check_status() } if (OB_SUCC(ret)) { - if (is_timeout()) { + if (OB_UNLIKELY((OB_SUCCESS != (ret = CHECK_MEM_STATUS())))) { + } else if (is_timeout()) { ret = OB_TIMEOUT; } else { if (WS_OUT_OF_THROTTLE == check_wait()) { diff --git a/src/pl/ob_pl_resolver.cpp b/src/pl/ob_pl_resolver.cpp index a35fc1357..fea164da1 100644 --- a/src/pl/ob_pl_resolver.cpp +++ b/src/pl/ob_pl_resolver.cpp @@ -2592,6 +2592,8 @@ int ObPLResolver::build_record_type_by_table_schema(ObSchemaGetterGuard &schema_ if (column_schema.is_enum_or_set()) { OZ (pl_type.set_type_info(column_schema.get_extended_type_info())); } + data_type.set_collation_level( + ObRawExprUtils::get_column_collation_level(column_schema.get_data_type())); OX (pl_type.set_data_type(data_type)); } if (OB_SUCC(ret)) { @@ -10269,7 +10271,7 @@ int ObPLResolver::resolve_expr(const ParseNode *node, } } else if (need_cast) { bool need_wrap = false; - OZ (ObRawExprUtils::need_wrap_to_string(expr->get_result_type().get_type(), + OZ (ObRawExprUtils::need_wrap_to_string(expr->get_result_type(), data_type->get_obj_type(), true, need_wrap)); @@ -13886,6 +13888,7 @@ int ObPLResolver::make_var_from_access(const ObIArray &access_id OZ (c_expr->add_flag(IS_DYNAMIC_PARAM)); if (OB_SUCC(ret) && ob_is_enum_or_set_type(res_type.get_type())) { c_expr->add_flag(IS_ENUM_OR_SET); + c_expr->mark_enum_set_skip_build_subschema(); } OZ (c_expr->extract_info()); OX (expr = c_expr); @@ -14080,6 +14083,10 @@ int ObPLResolver::convert_pltype_to_restype(ObIAllocator &alloc, result_type->set_collation_type(data_type->get_collation_type()); result_type->set_collation_level(data_type->get_collation_level()); result_type->set_scale(data_type->get_scale()); + } else if (ob_is_enumset_tc(result_type->get_type())) { + result_type->set_collation_type(data_type->get_collation_type()); + result_type->set_collation_level(data_type->get_collation_level()); + result_type->set_accuracy(data_type->get_accuracy()); } } } diff --git a/src/share/ob_lob_access_utils.h b/src/share/ob_lob_access_utils.h index 7c78a7af0..3457522d3 100644 --- a/src/share/ob_lob_access_utils.h +++ b/src/share/ob_lob_access_utils.h @@ -261,7 +261,7 @@ public: // Notice: // 1. all lobs created by this class should be temp lobs // 2. if has_lob_header_ is false, the text result should be 4.0 compatible - int init(const int64_t res_len, ObIAllocator *allocator = NULL); + virtual int init(const int64_t res_len, ObIAllocator *allocator = NULL); int init(const int64_t res_len, ObString &res_buffer); // copy existent loc to result diff --git a/src/share/ob_rpc_struct.cpp b/src/share/ob_rpc_struct.cpp index 6d002c414..af5ef5ce8 100644 --- a/src/share/ob_rpc_struct.cpp +++ b/src/share/ob_rpc_struct.cpp @@ -12530,6 +12530,28 @@ int ObTTLResponseArg::assign(const ObTTLResponseArg &other) return ret; } +OB_SERIALIZE_MEMBER(ObSeqCleanCacheRes, inited_, with_prefetch_node_, cache_node_, prefetch_node_); + +ObSeqCleanCacheRes::ObSeqCleanCacheRes() + : inited_(false), with_prefetch_node_(false), cache_node_(), prefetch_node_() +{ +} + +int ObSeqCleanCacheRes::assign(const ObSeqCleanCacheRes &other) +{ + int ret = OB_SUCCESS; + if (this == &other) { + } else if (OB_FAIL(cache_node_.assign(other.cache_node_))) { + LOG_WARN("fail to assign cache node", K(ret)); + } else if (OB_FAIL(prefetch_node_.assign(other.prefetch_node_))) { + LOG_WARN("fail to assign prefetch node", K(ret)); + } else { + inited_ = other.inited_; + with_prefetch_node_ = other.with_prefetch_node_; + } + return ret; +} + OB_SERIALIZE_MEMBER(ObTTLRequestArg, cmd_code_, trigger_type_, task_id_, tenant_id_); int ObTTLRequestArg::assign(const ObTTLRequestArg &other) diff --git a/src/share/ob_rpc_struct.h b/src/share/ob_rpc_struct.h index e19594a1b..2cb4fbb7f 100644 --- a/src/share/ob_rpc_struct.h +++ b/src/share/ob_rpc_struct.h @@ -92,6 +92,7 @@ #endif #include "storage/tablelock/ob_table_lock_common.h" //ObTableLockPriority #include "storage/mview/ob_major_mv_merge_info.h" //ObMajorMVMergeInfo +#include "share/sequence/ob_sequence_cache.h" // ObSeqCleanCacheRes namespace oceanbase { @@ -12773,6 +12774,22 @@ public: uint8_t task_status_; int err_code_; }; + +struct ObSeqCleanCacheRes final { + OB_UNIS_VERSION(1); + +public: + ObSeqCleanCacheRes(); + int assign(const ObSeqCleanCacheRes &other); + TO_STRING_KV(K_(inited), K_(with_prefetch_node), K_(cache_node), K_(prefetch_node)); + +public: + bool inited_; + bool with_prefetch_node_; + share::SequenceCacheNode cache_node_; + share::SequenceCacheNode prefetch_node_; +}; + struct ObAdminUnlockMemberListOpArg final { OB_UNIS_VERSION(1); diff --git a/src/share/ob_srv_rpc_proxy.h b/src/share/ob_srv_rpc_proxy.h index 8b8595a80..2a693df64 100644 --- a/src/share/ob_srv_rpc_proxy.h +++ b/src/share/ob_srv_rpc_proxy.h @@ -242,7 +242,7 @@ public: #endif RPC_S(PR5 remote_write_ddl_inc_commit_log, OB_REMOTE_WRITE_DDL_INC_COMMIT_LOG, (obrpc::ObRpcRemoteWriteDDLIncCommitLogArg), ObRpcRemoteWriteDDLIncCommitLogRes); RPC_S(PR5 check_ls_can_offline, OB_CHECK_LS_CAN_OFFLINE, (obrpc::ObCheckLSCanOfflineArg)); - RPC_S(PR5 clean_sequence_cache, obrpc::OB_CLEAN_SEQUENCE_CACHE, (obrpc::UInt64)); + RPC_S(PR5 clean_sequence_cache, obrpc::OB_CLEAN_SEQUENCE_CACHE, (obrpc::UInt64), obrpc::ObSeqCleanCacheRes); RPC_S(PR5 register_tx_data, OB_REGISTER_TX_DATA, (ObRegisterTxDataArg), ObRegisterTxDataResult); RPC_S(PR5 query_ls_is_valid_member, OB_QUERY_LS_IS_VALID_MEMBER, (ObQueryLSIsValidMemberRequest), ObQueryLSIsValidMemberResponse); diff --git a/src/share/object/ob_obj_cast.cpp b/src/share/object/ob_obj_cast.cpp index e696a75bb..d5d726651 100644 --- a/src/share/object/ob_obj_cast.cpp +++ b/src/share/object/ob_obj_cast.cpp @@ -35,6 +35,8 @@ #include "sql/engine/expr/ob_expr_sql_udt_utils.h" #include "sql/engine/expr/ob_array_expr_utils.h" #include "sql/engine/expr/ob_array_cast.h" +#include "sql/engine/expr/ob_expr_json_func_helper.h" +#include "sql/engine/expr/ob_expr_type_to_str.h" #include "sql/engine/ob_exec_context.h" #include "lib/charset/ob_charset.h" #include "lib/geo/ob_geometry_cast.h" @@ -6811,6 +6813,74 @@ static int bit_geometry(const ObObjType expect_type, ObObjCastParams ¶ms, return ret; } +static bool is_enum_set_with_subschema(const ObObj &in) +{ + return in.get_scale() == ObEnumSetMeta::MetaState::READY; +} + +static OB_INLINE int common_enumset_string(const ObObj &in, + ObObjCastParams ¶ms, + ObTextStringResult &text_result) +{ + int ret = OB_SUCCESS; + const ObEnumSetMeta *meta = NULL; + const ObObjType in_type = in.get_type(); + if (0 == in.get_uint64()) { + // empty string, do nothing + } else { + const uint16_t subschema_id = in.get_meta().get_subschema_id(); + if (OB_ISNULL(params.exec_ctx_)) { + ret = OB_ERR_UNDEFINED; + LOG_WARN("exec ctx is null", K(ret)); + } else if (OB_FAIL(params.exec_ctx_->get_enumset_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (OB_ISNULL(meta) || OB_ISNULL(meta->get_str_values())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get meta", K(ret)); + } else if (ObEnumType == in_type) { + ret = ObExprEnumToStr::inner_to_str(in.get_uint64(), *meta->get_str_values(), text_result); + } else if (ObSetType == in_type) { + ret = ObExprSetToStr::inner_to_str(in.get_collation_type(), in.get_uint64(), + *meta->get_str_values(), text_result); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected expr type", K(ret), K(in_type)); + } + } + + return ret; +} + +static int enumset_enumset(const ObExpectType &expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out) +{ + int ret = OB_SUCCESS; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObEnumSetTC != ob_obj_type_class(expect_type.get_type()))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(ObVarcharType, false, params.allocator_v2_); + ObString es_str; + ObObj temp_obj; + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (FALSE_IT(temp_obj.set_varchar(es_str))) { + } else if (expect_type.get_type() == ObEnumType && + OB_FAIL(string_enum(expect_type, params, temp_obj, out))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } else if (expect_type.get_type() == ObSetType && + OB_FAIL(string_set(expect_type, params, temp_obj, out))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + //////////////////////////////////////////////////////////////// // enum -> XXX /*//来自同一个enum 列的obj转换使用应该使用该接口,来自不同enum列的转换使用enumsetinner_enum @@ -6991,8 +7061,8 @@ ObCastEnumOrSetFunc OB_CAST_ENUM_OR_SET[ObMaxTC][2] = }, { /*enumset tc -> enum_or_set*/ - cast_not_expected_enum_set,/*enum*/ - cast_not_expected_enum_set,/*set*/ + enumset_enumset,/*enum*/ + enumset_enumset,/*set*/ }, { /*enumset_inner tc -> enum_or_set*/ @@ -7165,6 +7235,84 @@ static int enumset_number(const ObObjType expect_type, ObObjCastParams ¶ms, return ret; } +static int enumset_datetime(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObDateTimeTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(ObVarcharType, false, params.allocator_v2_); + ObString es_str; + ObObj temp_obj; + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (FALSE_IT(temp_obj.set_varchar(es_str))) { + } else if (OB_FAIL(string_datetime(expect_type, params, temp_obj, out, cast_mode))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + +static int enumset_date(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObDateTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(ObVarcharType, false, params.allocator_v2_); + ObString es_str; + ObObj temp_obj; + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (FALSE_IT(temp_obj.set_varchar(es_str))) { + } else if (OB_FAIL(string_date(expect_type, params, temp_obj, out, cast_mode))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + +static int enumset_time(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObTimeTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(ObVarcharType, false, params.allocator_v2_); + ObString es_str; + ObObj temp_obj; + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (FALSE_IT(temp_obj.set_varchar(es_str))) { + } else if (OB_FAIL(string_time(expect_type, params, temp_obj, out, cast_mode))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + static int enumset_year(const ObObjType expect_type, ObObjCastParams ¶ms, const ObObj &in, ObObj &out, const ObCastMode cast_mode) { @@ -7182,6 +7330,63 @@ static int enumset_year(const ObObjType expect_type, ObObjCastParams ¶ms, return ret; } +static int enumset_string(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + ObLength res_length = -1; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObStringTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(expect_type, false, params.allocator_v2_); + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else { + ObString es_str; + text_result.get_result_buffer(es_str); + out.set_string(expect_type, es_str); + if (OB_SUCC(ret)) { + res_length = static_cast(out.get_string_len()); + out.set_collation_type(params.dest_collation_); + } + } + } + SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length); + UNUSED(cast_mode); + return ret; +} + +static int enumset_text(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObTextTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(ObVarcharType, false, params.allocator_v2_); + ObString es_str; + ObObj temp_obj; + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (FALSE_IT(temp_obj.set_varchar(es_str))) { + } else if (OB_FAIL(string_text(expect_type, params, temp_obj, out, cast_mode))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + static int enumset_bit(const ObObjType expect_type, ObObjCastParams ¶ms, const ObObj &in, ObObj &out, const ObCastMode cast_mode) { @@ -7202,6 +7407,59 @@ static int enumset_bit(const ObObjType expect_type, ObObjCastParams ¶ms, return ret; } +static int enumset_lob(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObLobTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(ObVarcharType, false, params.allocator_v2_); + ObString es_str; + ObObj temp_obj; + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (FALSE_IT(temp_obj.set_varchar(es_str))) { + } else if (OB_FAIL(string_lob(expect_type, params, temp_obj, out, cast_mode))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + + +static int enumset_json(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + if (!is_enum_set_with_subschema(in)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected cast", K(ret), K(in)); + } else if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() + || ObJsonTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type)); + } else { + ObTextStringResult text_result(ObVarcharType, false, params.allocator_v2_); + ObString es_str; + ObObj temp_obj; + if (OB_FAIL(common_enumset_string(in, params, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (FALSE_IT(temp_obj.set_varchar(es_str))) { + } else if (OB_FAIL(string_json(expect_type, params, temp_obj, out, cast_mode))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + static int get_uint64_from_enumset_inner(const ObObj &in, ObObj &out) { @@ -11305,14 +11563,14 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = enumset_float,/*float*/ enumset_double,/*double*/ enumset_number,/*number*/ - cast_not_expected,/*datetime*/ - cast_not_expected,/*date*/ - cast_not_expected,/*time*/ + enumset_datetime,/*datetime*/ + enumset_date,/*date*/ + enumset_time,/*time*/ enumset_year,/*year*/ - cast_not_expected,/*string*/ + enumset_string,/*string*/ cast_not_support,/*extend*/ cast_not_support,/*unknown*/ - cast_not_expected,/*text*/ + enumset_text,/*text*/ enumset_bit,/*bit*/ cast_not_expected,/*enumset*/ cast_not_expected,/*enumset_inner*/ @@ -11320,9 +11578,9 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*raw*/ cast_not_expected,/*interval*/ cast_not_expected,/*rowid*/ - cast_not_expected,/*lob*/ - cast_not_expected,/*json*/ - cast_not_expected,/*geometry*/ + enumset_lob,/*lob*/ + enumset_json,/*json*/ + cast_not_support,/*geometry*/ cast_not_expected,/*udt*/ enumset_decimalint,/*decimalint*/ cast_not_support,/*collection*/ diff --git a/src/share/parameter/ob_parameter_seed.ipp b/src/share/parameter/ob_parameter_seed.ipp index 90743b98e..af0861590 100644 --- a/src/share/parameter/ob_parameter_seed.ipp +++ b/src/share/parameter/ob_parameter_seed.ipp @@ -420,6 +420,11 @@ DEF_BOOL(_optimizer_sortmerge_join_enabled, OB_TENANT_PARAMETER, "True", DEF_BOOL(_nested_loop_join_enabled, OB_TENANT_PARAMETER, "True", "enable/disable nested loop join", ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +// +DEF_BOOL(_enable_enum_set_subschema, OB_TENANT_PARAMETER, "True", + "Specifies whether to enable the enum/set extended type info is stored as subschema " + "and to activate the related new type cast logic behavior.", + ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); // tenant memtable consumption related DEF_INT(memstore_limit_percentage, OB_CLUSTER_PARAMETER, "0", "[0, 100)", @@ -2285,3 +2290,6 @@ ERRSIM_DEF_STR(errsim_rebuild_addr, OB_CLUSTER_PARAMETER, "", DEF_BOOL(_enable_adaptive_auto_dop, OB_CLUSTER_PARAMETER, "False", "Enable or disable adaptive auto dop feature.", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_INT(query_memory_limit_percentage, OB_TENANT_PARAMETER, "50", "[0,100]", + "the percentage of tenant memory that can be used by a single SQL. The default value is 50. Range: [0,100]", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); diff --git a/src/share/schema/ob_sequence_sql_service.cpp b/src/share/schema/ob_sequence_sql_service.cpp index a7c42403f..93f47ed07 100644 --- a/src/share/schema/ob_sequence_sql_service.cpp +++ b/src/share/schema/ob_sequence_sql_service.cpp @@ -25,6 +25,7 @@ #include "observer/ob_server_struct.h" #include "observer/ob_srv_network_frame.h" #include "share/ob_autoincrement_service.h" +#include "observer/ob_sql_client_decorator.h" namespace oceanbase { @@ -146,7 +147,44 @@ int ObSequenceSqlService::get_sequence_sync_value(const uint64_t tenant_id, return ret; } -int ObSequenceSqlService::clean_sequence_cache(uint64_t tenant_id, uint64_t sequence_id) +int ObSequenceSqlService::get_lastest_local_cache(ObFixedArray &prefetch_nodes, + const SequenceCacheNode &target_cache_node, + const ObNumber &inner_next_value, + ObSeqCleanCacheRes &cache_res, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObNumber temp_diff; + ObNumber tmp_inner_value; + if (OB_FAIL(tmp_inner_value.from(inner_next_value, allocator))) { + LOG_WARN("fail to init tmp_inner_vale", K(ret)); + } + for (int i = 0; OB_SUCC(ret) && i < prefetch_nodes.count(); i++) { + const SequenceCacheNode &node = prefetch_nodes.at(i); + if (OB_FAIL(node.end().sub(node.start(), temp_diff, allocator))) { + LOG_WARN("fail calc sub", K(ret), K(node)); + } else { + if ((temp_diff >= static_cast(0) && node.start() >= target_cache_node.end()) + || (temp_diff < static_cast(0) && node.start() <= target_cache_node.end())) { + if (OB_FAIL(tmp_inner_value.sub(temp_diff, tmp_inner_value, allocator))) { + LOG_WARN("fail calc sub", K(ret), K(tmp_inner_value), K(temp_diff)); + } + } + } + } + if (OB_SUCC(ret) && tmp_inner_value == target_cache_node.end()) { + if (OB_FAIL(cache_res.cache_node_.assign(target_cache_node))) { + LOG_WARN("faul to assign cache_node"); + } + cache_res.inited_ = true; + } + return ret; +} + +int ObSequenceSqlService::clean_sequence_cache(uint64_t tenant_id, uint64_t sequence_id, + ObNumber &inner_next_value, + ObSeqCleanCacheRes &cache_res, + ObIAllocator &allocator) { int ret = OB_SUCCESS; ObSEArray server_list; @@ -162,22 +200,142 @@ int ObSequenceSqlService::clean_sequence_cache(uint64_t tenant_id, uint64_t sequ } else if (OB_FAIL(srv_rpc_proxy.init(GCTX.net_frame_->get_req_transport(), GCTX.self_addr()))) { LOG_WARN("fail to init srv rpc proxy", KR(ret)); } else { + ObSeqCleanCacheRes temp_cache_res; + ObNumber min_diff; + ObNumber temp_diff; + SequenceCacheNode target_cache_node; + ObFixedArray prefetch_nodes(allocator); + if (OB_FAIL(prefetch_nodes.init(server_list.count()))) { + LOG_WARN("fail to init prefetch_nodes", K(ret)); + } else if (OB_FAIL(min_diff.from(INT64_MAX, allocator))) { + LOG_WARN("fail to init min_diff", K(ret)); + } for (int i = 0; OB_SUCC(ret) && i < server_list.count(); ++i) { + temp_cache_res.inited_ = false; const uint64_t timeout = THIS_WORKER.get_timeout_remain(); if (OB_FAIL(srv_rpc_proxy .to(server_list.at(i)) .by(tenant_id) .timeout(timeout) - .clean_sequence_cache(sequence_id))) { + .clean_sequence_cache(sequence_id, temp_cache_res))) { if (is_timeout_err(ret) || is_server_down_error(ret)) { LOG_WARN("rpc call time out, ignore the error", "server", server_list.at(i), K(tenant_id), K(sequence_id), K(ret)); ret = OB_SUCCESS; + } else if (ret == OB_NOT_SUPPORTED) { + // The new and old rpc are incompatible. The old rpc may not return results, but the cache + // will be cleared. + LOG_WARN("During upgrade, new and old rpc are incompatible, ignore the error", + "server", server_list.at(i), K(tenant_id), K(sequence_id), K(ret)); + ret = OB_SUCCESS; } else { LOG_WARN("clean sequnece cache failed", K(ret), K(sequence_id), K(server_list.at(i))); } + } else if (!temp_cache_res.inited_) { + // do nothing + } else if (temp_cache_res.with_prefetch_node_ + && OB_FAIL(prefetch_nodes.push_back(temp_cache_res.prefetch_node_))) { + LOG_WARN("fail to push back prefetch cache node", K(ret)); + } else if (OB_FAIL( + inner_next_value.sub(temp_cache_res.cache_node_.end(), temp_diff, allocator))) { + LOG_WARN("fail calc sub", K(ret), K(inner_next_value), K(temp_cache_res)); + } else if (temp_diff.abs() < min_diff) { + if (OB_FAIL(min_diff.from(temp_diff.abs(), allocator))) { + LOG_WARN("fail to set min_diff", K(ret)); + } else if (OB_FAIL(target_cache_node.assign(temp_cache_res.cache_node_))) { + LOG_WARN("fail to assign cache node", K(ret)); + } } } + if (OB_SUCC(ret) + && OB_FAIL(get_lastest_local_cache(prefetch_nodes, target_cache_node, inner_next_value, + cache_res, allocator))) { + LOG_WARN("fail to get lastest local cache", K(ret)); + } + } + return ret; +} + +int ObSequenceSqlService::clean_and_write_back_cache(common::ObISQLClient *sql_client, + const ObSequenceSchema &sequence_schema, + bool &need_write_back, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + uint64_t sequence_id = sequence_schema.get_sequence_id(); + uint64_t tenant_id = sequence_schema.get_tenant_id(); + const uint64_t exec_tenant_id = ObSchemaUtils::get_exec_tenant_id(tenant_id); + const char *tname = OB_ALL_SEQUENCE_VALUE_TNAME; + ObSqlString sql; + + ObNumber inner_next_value; // default to zero + ObSeqCleanCacheRes cache_res; + ObSQLClientRetryWeak sql_client_retry_weak(sql_client, exec_tenant_id, OB_ALL_SEQUENCE_VALUE_TID); + if (OB_SUCC(ret)) { + SMART_VAR(ObMySQLProxy::MySQLResult, res) + { + common::sqlclient::ObMySQLResult *result = NULL; + ObNumber tmp; + if (OB_FAIL(sql.assign_fmt("SELECT NEXT_VALUE FROM %s " + "WHERE SEQUENCE_ID = %lu FOR UPDATE", + tname, sequence_id))) { + STORAGE_LOG(WARN, "fail format sql", K(ret)); + } else if (OB_FAIL(sql_client_retry_weak.read(res, exec_tenant_id, sql.ptr()))) { + LOG_WARN("fail to execute sql", K(sql), K(ret)); + } else if (NULL == (result = res.get_result())) { + ret = OB_ENTRY_NOT_EXIST; + LOG_WARN("can't find sequence", K(tname), K(exec_tenant_id), K(sequence_id)); + } else if (OB_SUCCESS != (ret = result->next())) { + if (OB_ITER_END == ret) { + need_write_back = false; + ret = OB_SUCCESS; + LOG_WARN("get no line from all_sequence_value", K(ret)); + } else { + LOG_WARN("fail get next row", K(ret), K(tname), K(exec_tenant_id), K(sequence_id)); + } + } else { + EXTRACT_NUMBER_FIELD_MYSQL(*result, NEXT_VALUE, tmp); + if (OB_FAIL(ret)) { + LOG_WARN("fail get NEXT_VALUE", K(ret)); + } else if (OB_FAIL(inner_next_value.from(tmp, allocator))) { + LOG_WARN("fail deep copy next_val", K(tmp), K(ret)); + } else if (OB_ITER_END != (ret = result->next())) { + LOG_WARN("expected OB_ITER_END", K(ret)); + ret = (OB_SUCCESS == ret ? OB_ERR_UNEXPECTED : ret); + } else { + ret = OB_SUCCESS; + } + } + } + } + ObNumber write_val; + if (OB_FAIL(ret) || !need_write_back) { + // do nothing + } else if (OB_FAIL(clean_sequence_cache(tenant_id, sequence_id, inner_next_value, cache_res, + allocator))) { + LOG_WARN("clean sequence cache failed", K(ret)); + } else if (!cache_res.inited_) { + // do nothing + } else if (OB_FAIL(cache_res.cache_node_.start().add(sequence_schema.get_increment_by(), + write_val, allocator))) { + LOG_WARN("fail calc new_start", K(ret), K(inner_next_value), K(cache_res)); + } else if (write_val != inner_next_value) { + int64_t affected_rows = 0; + bool is_standby = false; + if (OB_FAIL(sql.assign_fmt("UPDATE %s SET next_value = %s " + "WHERE SEQUENCE_ID = %lu", + tname, write_val.format(), sequence_id))) { + LOG_WARN("format update sql fail", K(ret)); + } else if (OB_FAIL(ObShareUtil::table_check_if_tenant_role_is_standby(exec_tenant_id, is_standby))) { + LOG_WARN("fail to execute table_check_if_tenant_role_is_standby", KR(ret), K(exec_tenant_id)); + } else if (is_standby && OB_SYS_TENANT_ID != exec_tenant_id) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("can't write sys table now", K(ret), K(exec_tenant_id)); + } else if (OB_FAIL(sql_client->write(exec_tenant_id, sql.ptr(), affected_rows))) { + LOG_WARN("fail to execute sql", K(sql), K(ret)); + } else if (!is_single_row(affected_rows)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected value", K(affected_rows), K(sql), K(ret)); + } } return ret; } @@ -187,6 +345,7 @@ int ObSequenceSqlService::replace_sequence(const ObSequenceSchema &sequence_sche common::ObISQLClient *sql_client, bool alter_start_with, bool need_clean_cache, + bool need_write_back, const common::ObString *ddl_stmt_str) { int ret = OB_SUCCESS; @@ -266,14 +425,22 @@ int ObSequenceSqlService::replace_sequence(const ObSequenceSchema &sequence_sche K(ret)); } } - if (OB_SUCC(ret)) { - if (alter_start_with && OB_FAIL(alter_sequence_start_with(sequence_schema, *sql_client))) { + ObNumber inner_next_value; // default to zero + ObSeqCleanCacheRes cache_res; + if (OB_FAIL(ret)) { + // do nothing + } else if (alter_start_with) { + if (OB_FAIL(alter_sequence_start_with(sequence_schema, *sql_client))) { LOG_WARN("alter sequence for start with failed", K(ret)); - } else if (need_clean_cache && OB_FAIL(clean_sequence_cache(tenant_id, sequence_id))) { + } else if (OB_FAIL(clean_sequence_cache(tenant_id, sequence_id, inner_next_value, cache_res, + allocator))) { LOG_WARN("clean sequence cache failed", K(ret)); } + } else if (need_clean_cache + && OB_FAIL(clean_and_write_back_cache(sql_client, sequence_schema, need_write_back, + allocator))) { + LOG_WARN("fail to clean and write back cache", K(ret)); } - // log operation if (OB_SUCC(ret)) { ObSchemaOperation opt; diff --git a/src/share/schema/ob_sequence_sql_service.h b/src/share/schema/ob_sequence_sql_service.h index 9a6f89011..a0d55ab84 100644 --- a/src/share/schema/ob_sequence_sql_service.h +++ b/src/share/schema/ob_sequence_sql_service.h @@ -15,6 +15,9 @@ #include "ob_ddl_sql_service.h" #include "lib/number/ob_number_v2.h" +#include "share/ob_rpc_struct.h" + +using namespace oceanbase::common::number; namespace oceanbase { @@ -45,6 +48,7 @@ public: common::ObISQLClient *sql_client, bool alter_start_with, bool need_clean_cache, + bool need_write_back, const common::ObString *ddl_stmt_str = NULL); virtual int delete_sequence(const uint64_t tenant_id, const uint64_t database_id, @@ -64,8 +68,10 @@ public: common::ObISQLClient &sql_client, ObIAllocator &allocator, common::number::ObNumber &next_value); - int clean_sequence_cache(uint64_t tenant_id, uint64_t sequence_id); private: + int clean_and_write_back_cache(common::ObISQLClient *sql_client, + const ObSequenceSchema &sequence_schema, bool &need_write_back, + ObIAllocator &allocator); int add_sequence(common::ObISQLClient &sql_client, const ObSequenceSchema &sequence_schema, const bool only_history, const uint64_t *old_sequence_id); int add_sequence_to_value_table(const uint64_t tenant_id, @@ -74,6 +80,13 @@ private: const uint64_t new_sequence_id, common::ObISQLClient &sql_client, ObIAllocator &allocator); + int clean_sequence_cache(uint64_t tenant_id, uint64_t sequence_id, ObNumber &inner_next_value, + obrpc::ObSeqCleanCacheRes &cache_res, ObIAllocator &allocator); + + int get_lastest_local_cache(ObFixedArray &prefetch_nodes, + const SequenceCacheNode &target_cache_node, const ObNumber &inner_next_value, + obrpc::ObSeqCleanCacheRes &cache_res, ObIAllocator &allocator); + private: DISALLOW_COPY_AND_ASSIGN(ObSequenceSqlService); }; diff --git a/src/share/sequence/ob_sequence_cache.cpp b/src/share/sequence/ob_sequence_cache.cpp index 528f48052..fc3a03f69 100644 --- a/src/share/sequence/ob_sequence_cache.cpp +++ b/src/share/sequence/ob_sequence_cache.cpp @@ -17,12 +17,59 @@ #include "share/schema/ob_schema_struct.h" #include "lib/worker.h" #include "share/ob_errno.h" +#include "share/ob_rpc_struct.h" using namespace oceanbase::common; using namespace oceanbase::common::number; using namespace oceanbase::share; using namespace oceanbase::share::schema; +OB_DEF_SERIALIZE(SequenceCacheNode) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(start_); + OB_UNIS_ENCODE(end_); + return ret; +} + +OB_DEF_DESERIALIZE(SequenceCacheNode) +{ + int ret = OB_SUCCESS; + share::ObSequenceValue start; + share::ObSequenceValue end; + OB_UNIS_DECODE(start); + OB_UNIS_DECODE(end); + // deep copy is needed to ensure that the memory of start and end will not be reclaimed + if (OB_FAIL(ret)) { + } else if (OB_FAIL(start_.assign(start))) { + LOG_WARN("fail to assign start", K(ret)); + } else if (OB_FAIL(end_.assign(end))) { + LOG_WARN("fail to assign end", K(ret)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(SequenceCacheNode) +{ + int64_t len = 0; + OB_UNIS_ADD_LEN(start_); + OB_UNIS_ADD_LEN(end_); + return len; +} + +int SequenceCacheNode::assign(const SequenceCacheNode &other) +{ + int ret = OB_SUCCESS; + if (this == &other) { + } else if (OB_FAIL(start_.assign(other.start_))) { + LOG_WARN("fail to assign start", K(ret)); + } else if (OB_FAIL(end_.assign(other.end_))) { + LOG_WARN("fail to assign end", K(ret)); + } + return ret; +} + + ObSequenceCache::ObSequenceCache() : inited_(false), cache_mutex_(common::ObLatchIds::SEQUENCE_CACHE_LOCK) @@ -260,8 +307,10 @@ int ObSequenceCache::refill_sequence_cache(const ObSequenceSchema &schema, need_refetch = false; if (OB_FAIL(dml_proxy_.next_batch(schema.get_tenant_id(), schema.get_sequence_id(), + schema.get_schema_version(), schema.get_sequence_option(), - next_range))) { + next_range, + cache))) { LOG_WARN("fail get next sequence batch", K(schema), K(ret)); } else { // 判断是否需要重取,确保取得的值够一次 increment @@ -324,13 +373,16 @@ int ObSequenceCache::refill_sequence_cache(const ObSequenceSchema &schema, int ObSequenceCache::prefetch_sequence_cache(const ObSequenceSchema &schema, - ObSequenceCacheItem &cache) + ObSequenceCacheItem &cache, + ObSequenceCacheItem &old_cache) { int ret = OB_SUCCESS; if (OB_FAIL(dml_proxy_.prefetch_next_batch(schema.get_tenant_id(), schema.get_sequence_id(), + schema.get_schema_version(), schema.get_sequence_option(), - cache.prefetch_node_))) { + cache.prefetch_node_, + old_cache))) { LOG_WARN("fail get next sequence batch", K(schema), K(ret)); } else { cache.last_refresh_ts_ = ObTimeUtility::current_time(); @@ -362,26 +414,44 @@ int ObSequenceCache::get_item(CacheItemKey &key, ObSequenceCacheItem *&item) return ret; } -int ObSequenceCache::del_item(CacheItemKey &key) +int ObSequenceCache::del_item(uint64_t tenant_id, CacheItemKey &key, obrpc::ObSeqCleanCacheRes &cache_res) { int ret = OB_SUCCESS; - // LOG_INFO("XXXX: del item", K(key)); - // auto func = [&] (CacheItemKey &mykey, ObSequenceCacheItem *value) { - // LOG_INFO("XXXX: list items in cache", K(mykey), K(*value)); - // return true; - // }; - // sequence_cache_.map(func); - if (OB_ENTRY_EXIST == (ret = sequence_cache_.contains_key(key))) { lib::ObMutexGuard guard(cache_mutex_); // 加锁再次确认,避免并发加入新节点 - if (OB_ENTRY_EXIST == (ret = sequence_cache_.contains_key(key))) { - if (OB_FAIL(sequence_cache_.del(key))) { - LOG_WARN("del sequence cache failed", K(ret)); + ObSequenceCacheItem *item = nullptr; + uint64_t compat_version = 0; + if (OB_FAIL(sequence_cache_.get(key, item))) { + // no cache, do nothing + } else if (OB_FAIL(sequence_cache_.del(key))) { + LOG_WARN("del sequence cache failed", K(ret)); + } else if (FAILEDx(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", KR(ret), K(tenant_id)); + } else if ((compat_version >= MOCK_DATA_VERSION_4_2_5_0 + && compat_version < DATA_VERSION_4_3_0_0) + || compat_version >= DATA_VERSION_4_3_5_0) { + lib::ObMutexGuard guard(item->alloc_mutex_); + if (OB_FAIL(ret) || item->last_refresh_ts_ <= SequenceCacheStatus::INITED) { + // do nothing + } else if (OB_FAIL(cache_res.cache_node_.set_start(item->last_number()))) { + LOG_WARN("fail to set cache value", K(ret)); + } else if (OB_FAIL(cache_res.cache_node_.set_end(item->curr_node_.end()))) { + LOG_WARN("fail to set cache end", K(ret)); + } else if (item->with_prefetch_node_ + && OB_FAIL(cache_res.prefetch_node_.assign(item->prefetch_node_))) { + LOG_WARN("fail to assign prefetch node", K(ret)); + } else { + item->last_refresh_ts_ = SequenceCacheStatus::DELETED; + cache_res.inited_ = true; + cache_res.with_prefetch_node_ = item->with_prefetch_node_; } } else { LOG_INFO("fail check if key in cache", K(ret), K(key)); } + if (nullptr != item) { + sequence_cache_.revert(item); + } } return (ret == OB_ENTRY_NOT_EXIST) ? OB_SUCCESS : ret; } @@ -409,98 +479,104 @@ int ObSequenceCache::nextval(const ObSequenceSchema &schema, } else if (OB_ISNULL(item)) { ret = OB_ERR_UNEXPECTED; } else { - lib::ObMutexGuard guard(item->alloc_mutex_); - /* refill_sequence_cache 期间禁止调度器挂起 query */ - lib::DisableSchedInterGuard sched_guard; - { - LOG_DEBUG("nextval", K(schema)); + lib::ObMutexGuard guard(item->fetch_); + item->alloc_mutex_.lock(); + if (item->last_refresh_ts_ == SequenceCacheStatus::DELETED) { + ret = OB_AUTOINC_CACHE_NOT_EQUAL; + LOG_WARN("cache has been cleared", K(ret), K(*item)); + } else { + /* refill_sequence_cache 期间禁止调度器挂起 query */ + lib::DisableSchedInterGuard sched_guard; + { + LOG_DEBUG("nextval", K(schema)); - // step 1. 从 cache 中获取下一个值 - ret = move_next(schema, *item, allocator, nextval); + // step 1. 从 cache 中获取下一个值 + ret = move_next(schema, *item, allocator, nextval); - // setp 2. cache 中的值已经使用完,需要重填 cache - // 注意:预取功能正常的情况下,不会走到这个分支 - if (OB_SIZE_OVERFLOW == ret) { - LOG_INFO("no more avaliable value in current cache, try refill cache", K(*item), K(ret)); - if (OB_FAIL(refill_sequence_cache(schema, allocator, *item))) { - LOG_WARN("fail refill sequence cache", K(*item), K(ret)); - } else if (OB_FAIL(move_next(schema, *item, allocator, nextval))) { - LOG_WARN("fail move next", K(*item), K(ret)); - } + // setp 2. cache 中的值已经使用完,需要重填 cache + // 注意:预取功能正常的情况下,不会走到这个分支 if (OB_SIZE_OVERFLOW == ret) { - ret = OB_ERR_SEQ_VALUE_EXCEED_LIMIT; - if (schema.get_increment_by() < static_cast(0)) { - LOG_USER_ERROR(OB_ERR_SEQ_VALUE_EXCEED_LIMIT, "MINVALUE"); - } else if (schema.get_increment_by() > static_cast(0)) { - LOG_USER_ERROR(OB_ERR_SEQ_VALUE_EXCEED_LIMIT, "MAXVALUE"); + LOG_INFO("no more avaliable value in current cache, try refill cache", K(*item), K(ret)); + if (OB_FAIL(refill_sequence_cache(schema, allocator, *item))) { + LOG_WARN("fail refill sequence cache", K(*item), K(ret)); + } else if (OB_FAIL(move_next(schema, *item, allocator, nextval))) { + LOG_WARN("fail move next", K(*item), K(ret)); + } + if (OB_SIZE_OVERFLOW == ret) { + ret = OB_ERR_SEQ_VALUE_EXCEED_LIMIT; + if (schema.get_increment_by() < static_cast(0)) { + LOG_USER_ERROR(OB_ERR_SEQ_VALUE_EXCEED_LIMIT, "MINVALUE"); + } else if (schema.get_increment_by() > static_cast(0)) { + LOG_USER_ERROR(OB_ERR_SEQ_VALUE_EXCEED_LIMIT, "MAXVALUE"); + } + } + } + + // step 3. 尝试预取 + if (OB_SUCC(ret) && + !item->prefetching_ && + schema.get_cache_size() > static_cast(1) && /* cache size = 1 时禁止 prefetch */ + schema.get_order_flag() == false /* 有 order 时禁止 prefetch */) { + if (OB_UNLIKELY(!item->with_prefetch_node_)) { + //const int64_t rest = std::abs(item->curr_node_.end() - item->curr_node_.start()); + //const int64_t full = std::abs(schema.get_increment_by() * schema.get_cache_size()); + ObNumber rest; + ObNumber full; + ObNumberCalc calc(item->curr_node_.end(), allocator); + // 拍脑袋的值,表示使用了 1/2 的值后就开始预取 + static const int64_t PREFETCH_OP_THRESHOLD = 2; + // + // const int64_t rest = std::abs(item->curr_node_.end_ - item->curr_node_.start_) * PREFETCH_OP_THRESHOLD; + // const int64_t full = std::abs(schema.get_increment_by() * schema.get_cache_size()); + // if (rest < full) { + // enable prefetch + // } + // + if (OB_FAIL(calc.sub(item->curr_node_.start()).mul(PREFETCH_OP_THRESHOLD).get_result(rest))) { + LOG_WARN("fail do number sub", K(ret)); + } else if (OB_FAIL(schema.get_increment_by().mul(schema.get_cache_size(), full, allocator))) { + LOG_WARN("fail do number multiply", K(ret)); + } else if (rest.abs() <= full.abs()) { + item->prefetching_ = true; + need_prefetch = true; + } } } } - // step 3. 尝试预取 - if (OB_SUCC(ret) && - !item->prefetching_ && - schema.get_cache_size() > static_cast(1) && /* cache size = 1 时禁止 prefetch */ - schema.get_order_flag() == false /* 有 order 时禁止 prefetch */) { - if (OB_UNLIKELY(!item->with_prefetch_node_)) { - //const int64_t rest = std::abs(item->curr_node_.end() - item->curr_node_.start()); - //const int64_t full = std::abs(schema.get_increment_by() * schema.get_cache_size()); - ObNumber rest; - ObNumber full; - ObNumberCalc calc(item->curr_node_.end(), allocator); - // 拍脑袋的值,表示使用了 1/2 的值后就开始预取 - static const int64_t PREFETCH_OP_THRESHOLD = 2; - // - // const int64_t rest = std::abs(item->curr_node_.end_ - item->curr_node_.start_) * PREFETCH_OP_THRESHOLD; - // const int64_t full = std::abs(schema.get_increment_by() * schema.get_cache_size()); - // if (rest < full) { - // enable prefetch - // } - // - if (OB_FAIL(calc.sub(item->curr_node_.start()).mul(PREFETCH_OP_THRESHOLD).get_result(rest))) { - LOG_WARN("fail do number sub", K(ret)); - } else if (OB_FAIL(schema.get_increment_by().mul(schema.get_cache_size(), full, allocator))) { - LOG_WARN("fail do number multiply", K(ret)); - } else if (rest.abs() <= full.abs()) { - item->prefetching_ = true; - need_prefetch = true; - } - } - } - } - - if (OB_SUCC(ret) && need_prefetch) { - ObSequenceCacheItem mock_item; - if (OB_FAIL(prefetch_sequence_cache(schema, mock_item))) { - int prefetch_err = ret; - ret = OB_SUCCESS; - LOG_WARN("fail refill sequence cache. ignore prefrech error", K(prefetch_err), K(ret)); - } else { - LOG_INFO("dump item", K(mock_item), K(*item)); - if (item->with_prefetch_node_) { - LOG_INFO("new item has been fetched by other, ignore"); + if (OB_SUCC(ret) && need_prefetch) { + ObSequenceCacheItem mock_item; + if (OB_FAIL(prefetch_sequence_cache(schema, mock_item, *item))) { + int prefetch_err = ret; + ret = OB_SUCCESS; + LOG_WARN("fail refill sequence cache. ignore prefrech error", K(prefetch_err), K(ret)); } else { - item->last_refresh_ts_ = mock_item.last_refresh_ts_; - item->with_prefetch_node_ = true; - if (OB_FAIL(item->prefetch_node_.set_start(mock_item.prefetch_node_.start()))) { - LOG_WARN("fail set start for pretch node", K(ret)); - } else if (OB_FAIL(item->prefetch_node_.set_end(mock_item.prefetch_node_.end()))) { - LOG_WARN("fail set end for pretch node", K(ret)); + LOG_INFO("dump item", K(mock_item), K(*item)); + if (item->with_prefetch_node_) { + LOG_INFO("new item has been fetched by other, ignore"); + } else { + item->last_refresh_ts_ = mock_item.last_refresh_ts_; + item->with_prefetch_node_ = true; + if (OB_FAIL(item->prefetch_node_.set_start(mock_item.prefetch_node_.start()))) { + LOG_WARN("fail set start for pretch node", K(ret)); + } else if (OB_FAIL(item->prefetch_node_.set_end(mock_item.prefetch_node_.end()))) { + LOG_WARN("fail set end for pretch node", K(ret)); + } } } + item->prefetching_ = false; } - item->prefetching_ = false; } } - if (nullptr != item) { + item->alloc_mutex_.unlock(); sequence_cache_.revert(item); } return ret; } -int ObSequenceCache::remove(uint64_t tenant_id, uint64_t sequence_id) +int ObSequenceCache::remove(uint64_t tenant_id, uint64_t sequence_id, obrpc::ObSeqCleanCacheRes &cache_res) { CacheItemKey key(tenant_id, sequence_id); - return del_item(key); + return del_item(tenant_id, key, cache_res); } diff --git a/src/share/sequence/ob_sequence_cache.h b/src/share/sequence/ob_sequence_cache.h index 6e81558f0..060d32bc8 100644 --- a/src/share/sequence/ob_sequence_cache.h +++ b/src/share/sequence/ob_sequence_cache.h @@ -26,6 +26,10 @@ namespace common class ObMySQLProxy; class ObMySQLTransaction; } +namespace obrpc +{ + struct ObSeqCleanCacheRes; +} namespace share { namespace schema @@ -37,10 +41,12 @@ class ObMultiVersionSchemaService; struct SequenceCacheNode { + OB_UNIS_VERSION(1); +public: SequenceCacheNode() : start_(), end_() {} - + int assign(const SequenceCacheNode &other); void reset() { } @@ -95,6 +101,12 @@ public: uint64_t key_; }; +enum SequenceCacheStatus +{ + DELETED, + INITED +}; + struct ObSequenceCacheItem : public common::LinkHashValue { public: @@ -102,8 +114,9 @@ public: : prefetching_(false), with_prefetch_node_(false), base_on_last_number_(false), - last_refresh_ts_(0), + last_refresh_ts_(INITED), alloc_mutex_(common::ObLatchIds::SEQUENCE_VALUE_ALLOC_LOCK), + fetch_(common::ObLatchIds::SEQUENCE_VALUE_FETCH_LOCK), last_number_() {} int combine_prefetch_node() @@ -140,6 +153,7 @@ public: // 记录上次取得的值,用于 cycle 模式下判断下次取值是否需要加上 increment_by int64_t last_refresh_ts_; lib::ObMutex alloc_mutex_; + lib::ObMutex fetch_; private: ObSequenceValue last_number_; public: @@ -167,15 +181,17 @@ public: int nextval(const share::schema::ObSequenceSchema &schema, common::ObIAllocator &allocator, // 用于各种临时计算 ObSequenceValue &nextval); - int remove(uint64_t tenant_id, uint64_t sequence_id); + int remove(uint64_t tenant_id, uint64_t sequence_id, obrpc::ObSeqCleanCacheRes &cache_res); + private: /* functions */ int get_item(CacheItemKey &key, ObSequenceCacheItem *&item); - int del_item(CacheItemKey &key); + int del_item(uint64_t tenant_id, CacheItemKey &key, obrpc::ObSeqCleanCacheRes &cache_res); int prefetch_sequence_cache(const schema::ObSequenceSchema &schema, - ObSequenceCacheItem &cache); + ObSequenceCacheItem &cache, + ObSequenceCacheItem &old_cache); int find_sequence_cache(const schema::ObSequenceSchema &schema, ObSequenceCacheItem &cache); int move_next(const schema::ObSequenceSchema &schema, diff --git a/src/share/sequence/ob_sequence_ddl_proxy.cpp b/src/share/sequence/ob_sequence_ddl_proxy.cpp index 5cd124601..57ad050da 100644 --- a/src/share/sequence/ob_sequence_ddl_proxy.cpp +++ b/src/share/sequence/ob_sequence_ddl_proxy.cpp @@ -252,15 +252,15 @@ int ObSequenceDDLProxy::alter_sequence( const ObSequenceOption &opt_old = cur_sequence_schema->get_sequence_option(); bool alter_start_with = opt_bitset.has_member(ObSequenceArg::START_WITH) || opt_bitset.has_member(ObSequenceArg::RESTART); - bool need_clean_cache = opt_bitset.has_member(ObSequenceArg::START_WITH) || - opt_bitset.has_member(ObSequenceArg::RESTART) || - (opt_bitset.has_member(ObSequenceArg::INCREMENT_BY) - && opt_old.get_cache_size() <= static_cast(1)) || - (opt_bitset.has_member(ObSequenceArg::ORDER) && !opt_old.get_order_flag()); + // Only in nocache mode, when the step is not changed, there is no need to clear the cache + bool need_clean_cache = !(opt_old.get_cache_size() <= static_cast(1) + && !opt_bitset.has_member(ObSequenceArg::INCREMENT_BY)); + // in noorder cycle mode, cannot decide to write back which cache + bool need_write_back = !(opt_old.get_cycle_flag() && !opt_old.get_order_flag()); seq_schema.set_sequence_id(sequence_id); seq_schema.set_schema_version(new_schema_version); - if (OB_FAIL(schema_service->get_sequence_sql_service().replace_sequence( - seq_schema, false, &trans, alter_start_with, need_clean_cache, ddl_stmt_str))) { + if (OB_FAIL(schema_service->get_sequence_sql_service().replace_sequence(seq_schema, + false, &trans, alter_start_with, need_clean_cache, need_write_back, ddl_stmt_str))) { LOG_WARN("alter sequence info failed", K(seq_schema.get_sequence_name()), K(ret)); } else { LOG_INFO("alter sequence", K(lbt()), K(seq_schema)); @@ -378,7 +378,7 @@ int ObSequenceDDLProxy::rename_sequence(share::schema::ObSequenceSchema &seq_sch } else { seq_schema.set_schema_version(new_schema_version); if (OB_FAIL(schema_service->get_sequence_sql_service().replace_sequence( - seq_schema, true, &trans, false, false, ddl_stmt_str))) { + seq_schema, true, &trans, false, false, false, ddl_stmt_str))) { LOG_WARN("rename sequence info failed", K(ret), K(seq_schema.get_sequence_name())); } else { LOG_INFO("rename sequence", K(lbt()), K(seq_schema)); diff --git a/src/share/sequence/ob_sequence_dml_proxy.cpp b/src/share/sequence/ob_sequence_dml_proxy.cpp index 76d21af9e..362c61f4d 100644 --- a/src/share/sequence/ob_sequence_dml_proxy.cpp +++ b/src/share/sequence/ob_sequence_dml_proxy.cpp @@ -97,8 +97,10 @@ int ObSequenceDMLProxy::set_pre_op_timeout(common::ObTimeoutCtx &ctx) int ObSequenceDMLProxy::next_batch( const uint64_t tenant_id, const uint64_t sequence_id, + const int64_t schema_version, const share::ObSequenceOption &option, - SequenceCacheNode &cache_range) + SequenceCacheNode &cache_range, + ObSequenceCacheItem &old_cache) { int ret = OB_SUCCESS; const char *tname = OB_ALL_SEQUENCE_VALUE_TNAME; @@ -127,6 +129,7 @@ int ObSequenceDMLProxy::next_batch( cache_size.shadow_copy(option.get_cache_size()); } + old_cache.alloc_mutex_.unlock(); if (OB_FAIL(ret)) { // pass } else if (!inited_) { @@ -187,6 +190,31 @@ int ObSequenceDMLProxy::next_batch( } } + old_cache.alloc_mutex_.lock(); + if (OB_SUCC(ret)) { + SMART_VAR(ObMySQLProxy::MySQLResult, res) + { + ObSqlString sql; + ObMySQLResult *result = NULL; + int64_t curr_version = OB_INVALID_VERSION; + if (OB_FAIL(sql.assign_fmt("SELECT schema_version " + "FROM %s WHERE sequence_id=%lu", + OB_ALL_SEQUENCE_OBJECT_TNAME, sequence_id))) { + LOG_WARN("fail to assign sql", KR(ret), K(tenant_id), K(sequence_id)); + } else if (OB_FAIL(sql_client->read(res, tenant_id, sql.ptr()))) { + LOG_WARN("fail to read", KR(ret), K(tenant_id), K(sql)); + } else if (NULL == (result = res.get_result())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get sql result", K(ret)); + } else if (OB_FAIL((*result).get_int("schema_version", curr_version))) { + LOG_WARN("fail to get schema_version", K(ret), K(tenant_id), K(sql)); + } else if (schema_version != curr_version) { + ret = OB_AUTOINC_CACHE_NOT_EQUAL; + LOG_WARN("schema is not up to date, need retry", K(ret)); + } + } + } + if (OB_SUCC(ret) && need_init_sequence_value_table) { // 首次从 all_sequence_object 表读取数据时,需要先向 // all_sequence_object 表中插入一行初始数据 @@ -306,16 +334,21 @@ int ObSequenceDMLProxy::next_batch( } if (OB_SUCC(ret)) { - OZ(cache_range.set_start(cache_inclusive_start)); - OZ(cache_range.set_end(cache_exclusive_end)); - LOG_INFO("get next sequence batch success", - K(tenant_id), - K(sequence_id), - "cache_inclusive_start", cache_inclusive_start.format(), - "cache_exclusive_end", cache_exclusive_end.format(), - "increment_by", increment_by.format(), - "cache_size", cache_size.format(), - K(ret)); + if (OB_UNLIKELY(increment_by > static_cast(0) && cache_inclusive_start > max_value) + || OB_UNLIKELY(increment_by < static_cast(0) && cache_inclusive_start < min_value)) { + ret = OB_AUTOINC_CACHE_NOT_EQUAL; + } else { + OZ(cache_range.set_start(cache_inclusive_start)); + OZ(cache_range.set_end(cache_exclusive_end)); + LOG_INFO("get next sequence batch success", + K(tenant_id), + K(sequence_id), + "cache_inclusive_start", cache_inclusive_start.format(), + "cache_exclusive_end", cache_exclusive_end.format(), + "increment_by", increment_by.format(), + "cache_size", cache_size.format(), + K(ret)); + } } return ret; @@ -324,8 +357,10 @@ int ObSequenceDMLProxy::next_batch( int ObSequenceDMLProxy::prefetch_next_batch( const uint64_t tenant_id, const uint64_t sequence_id, + const int64_t schema_version, const share::ObSequenceOption &option, - SequenceCacheNode &cache_range) + SequenceCacheNode &cache_range, + ObSequenceCacheItem &old_cache) { int ret = OB_SUCCESS; // set timeout for prefetch @@ -334,8 +369,10 @@ int ObSequenceDMLProxy::prefetch_next_batch( LOG_WARN("failed to set timeout", K(ret)); } else if (OB_FAIL(next_batch(tenant_id, sequence_id, + schema_version, option, - cache_range))) { + cache_range, + old_cache))) { LOG_WARN("fail prefetch sequence batch", K(tenant_id), K(sequence_id), K(option), K(ret)); } diff --git a/src/share/sequence/ob_sequence_dml_proxy.h b/src/share/sequence/ob_sequence_dml_proxy.h index a963b07e0..8fb8f7cb5 100644 --- a/src/share/sequence/ob_sequence_dml_proxy.h +++ b/src/share/sequence/ob_sequence_dml_proxy.h @@ -15,6 +15,7 @@ #include "lib/ob_define.h" #include "lib/utility/ob_macro_utils.h" +#include "lib/lock/ob_mutex.h" namespace oceanbase { @@ -34,6 +35,7 @@ namespace share { class ObSequenceOption; struct SequenceCacheNode; +struct ObSequenceCacheItem; namespace schema { class ObSchemaGetterGuard; @@ -58,17 +60,21 @@ public: */ int next_batch(const uint64_t tenant_id, const uint64_t sequence_id, + const int64_t schema_version, const share::ObSequenceOption &option, - SequenceCacheNode &cache_range); + SequenceCacheNode &cache_range, + ObSequenceCacheItem &old_cache); int prefetch_next_batch( const uint64_t tenant_id, const uint64_t sequence_id, + const int64_t schema_version, const share::ObSequenceOption &option, - SequenceCacheNode &cache_range); + SequenceCacheNode &cache_range, + ObSequenceCacheItem &old_cache); private: /* functions */ int set_pre_op_timeout(common::ObTimeoutCtx &ctx); - int init_sequence_value_table( + static int init_sequence_value_table( common::ObMySQLTransaction &trans, common::ObSQLClientRetryWeak &sql_client_retry_weak, common::ObIAllocator &allocator, diff --git a/src/share/sequence/ob_sequence_option.cpp b/src/share/sequence/ob_sequence_option.cpp index b543df006..1e129e9c8 100644 --- a/src/share/sequence/ob_sequence_option.cpp +++ b/src/share/sequence/ob_sequence_option.cpp @@ -129,4 +129,3 @@ int ObSequenceOption::assign(const share::ObSequenceOption &from) flag_ = from.flag_; return ret; } - diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index 14c20ac75..ab634585c 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -1000,6 +1000,8 @@ ob_set_subtarget(ob_sql executor executor/ob_task_runner_notifier_service.cpp executor/ob_task_spliter.cpp executor/ob_task_spliter_factory.cpp + executor/ob_memory_tracker.cpp + executor/ob_memory_tracker_wrapper.cpp ) ob_set_subtarget(ob_sql monitor diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index fe32b6587..b0946d709 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -980,7 +980,7 @@ int ObStaticEngineCG::generate_spec_final(ObLogicalOperator &op, ObOpSpec &spec) } } - if (PHY_NESTED_LOOP_CONNECT_BY == spec.type_ + if (PHY_CONNECT_BY == spec.type_ || PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX == spec.type_) { FOREACH_CNT_X(e, spec.calc_exprs_, OB_SUCC(ret)) { if (T_OP_PRIOR == (*e)->type_) { @@ -5824,15 +5824,15 @@ int ObStaticEngineCG::construct_hash_elements_for_connect_by(ObLogJoin &op, ObNL } else if (OB_ISNULL(left_op = op.get_child(0)) || OB_ISNULL(right_op = op.get_child(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child op is null", K(ret)); - } else if (OB_FAIL(spec.hash_key_exprs_.init(op.get_other_join_conditions().count()))) { + } else if (OB_FAIL(spec.hash_key_exprs_.init(op.get_equal_join_conditions().count()))) { LOG_WARN("failed to init hash key exprs", K(ret)); - } else if (OB_FAIL(spec.hash_probe_exprs_.init(op.get_other_join_conditions().count()))) { + } else if (OB_FAIL(spec.hash_probe_exprs_.init(op.get_equal_join_conditions().count()))) { LOG_WARN("failed to init hash probe exprs", K(ret)); } else { const ObRelIds &left_table_set = left_op->get_table_set(); const ObRelIds &right_table_set = right_op->get_table_set(); - for (int64_t i = 0; OB_SUCC(ret) && i < op.get_other_join_conditions().count(); i++) { - ObRawExpr *other_cond = op.get_other_join_conditions().at(i); + for (int64_t i = 0; OB_SUCC(ret) && i < op.get_equal_join_conditions().count(); i++) { + ObRawExpr *other_cond = op.get_equal_join_conditions().at(i); if (OB_ISNULL(other_cond)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("other condition is null", K(ret)); @@ -5882,7 +5882,11 @@ int ObStaticEngineCG::generate_spec(ObLogJoin &op, ObNLConnectBySpec &spec, cons int ret = OB_SUCCESS; UNUSED(in_root_job); const ObIArray &other_join_conds = op.get_other_join_conditions(); - if (OB_FAIL(generate_param_spec(op.get_nl_params(), spec.rescan_params_))) { + if (HASH_JOIN == op.get_join_algo() + && OB_FAIL(append(const_cast &>(other_join_conds), + op.get_equal_join_conditions()))) { + LOG_WARN("fail to push back hash join conditions", K(ret)); + } else if (OB_FAIL(generate_param_spec(op.get_nl_params(), spec.rescan_params_))) { LOG_WARN("failed to generate parameter", K(ret)); } else if (OB_FAIL(generate_pump_exprs(op, spec))) { LOG_WARN("failed to generate pump exprs", K(ret)); @@ -5890,7 +5894,8 @@ int ObStaticEngineCG::generate_spec(ObLogJoin &op, ObNLConnectBySpec &spec, cons LOG_WARN("failed to init join conditions", K(ret)); } else if (OB_FAIL(generate_rt_exprs(other_join_conds, spec.cond_exprs_))) { LOG_WARN("failed to generate condition rt exprs", K(ret)); - } else if (OB_FAIL(construct_hash_elements_for_connect_by(op, spec))) { + } else if (HASH_JOIN == op.get_join_algo() + && OB_FAIL(construct_hash_elements_for_connect_by(op, spec))) { LOG_WARN("construct_hash_elements_for_connect_by failed", K(ret)); } return ret; @@ -9131,7 +9136,7 @@ int ObStaticEngineCG::get_phy_op_type(ObLogicalOperator &log_op, ? PHY_NESTED_LOOP_JOIN : (op.get_nl_params().count() > 0 ? PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX - : PHY_NESTED_LOOP_CONNECT_BY); + : PHY_CONNECT_BY); break; } case MERGE_JOIN: { @@ -9152,11 +9157,15 @@ int ObStaticEngineCG::get_phy_op_type(ObLogicalOperator &log_op, } case HASH_JOIN: { int tmp_ret = OB_SUCCESS; - tmp_ret = OB_E(EventTable::EN_DISABLE_VEC_HASH_JOIN) OB_SUCCESS; - if (OB_SUCCESS == tmp_ret && use_rich_format) { - type = PHY_VEC_HASH_JOIN; + if (CONNECT_BY_JOIN == op.get_join_type()) { + type = PHY_CONNECT_BY; } else { - type = PHY_HASH_JOIN; + tmp_ret = OB_E(EventTable::EN_DISABLE_VEC_HASH_JOIN) OB_SUCCESS; + if (OB_SUCCESS == tmp_ret && use_rich_format) { + type = PHY_VEC_HASH_JOIN; + } else { + type = PHY_HASH_JOIN; + } } break; } diff --git a/src/sql/code_generator/ob_static_engine_expr_cg.cpp b/src/sql/code_generator/ob_static_engine_expr_cg.cpp index b7878c064..f7f9ffc37 100644 --- a/src/sql/code_generator/ob_static_engine_expr_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_expr_cg.cpp @@ -330,6 +330,16 @@ int ObStaticEngineExprCG::cg_expr_basic(const ObIArray &raw_exprs) if (ob_is_bit_tc(result_meta.get_type())) { rt_expr->obj_meta_.set_scale(rt_expr->datum_meta_.length_semantics_); } + if (OB_SUCC(ret) && ob_is_enumset_tc(result_meta.get_type())) { + ObObjMeta org_obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(raw_expr->get_result_type(), + op_cg_ctx_.session_, + org_obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + rt_expr->datum_meta_.cs_type_ = org_obj_meta.get_collation_type(); + } + } // init max_length_ rt_expr->max_length_ = raw_expr->get_result_type().get_length(); // init obj_datum_map_ diff --git a/src/sql/engine/expr/ob_datum_cast.cpp b/src/sql/engine/expr/ob_datum_cast.cpp index 567e08839..a7ccc1105 100644 --- a/src/sql/engine/expr/ob_datum_cast.cpp +++ b/src/sql/engine/expr/ob_datum_cast.cpp @@ -40,6 +40,8 @@ #include "sql/engine/expr/ob_expr_xml_func_helper.h" #include "pl/ob_pl.h" #include "pl/ob_pl_user_type.h" +#include "lib/enumset/ob_enum_set_meta.h" +#include "sql/engine/expr/ob_expr_type_to_str.h" #ifdef OB_BUILD_ORACLE_PL #include "pl/sys_package/ob_sdo_geometry.h" #endif @@ -2032,6 +2034,42 @@ static int common_string_lob(const ObExpr &expr, return ret; } +int get_enumset_meta(sql::ObEvalCtx &ctx, const ObObjMeta &obj_meta, const ObEnumSetMeta *&meta) { + int ret = OB_SUCCESS; + const uint16_t subschema_id = obj_meta.get_subschema_id(); + if (OB_FAIL(ctx.exec_ctx_.get_enumset_meta_by_subschema_id(subschema_id, meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (OB_ISNULL(meta) || OB_UNLIKELY(!meta->is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get meta", K(ret)); + } + return ret; +} + +static OB_INLINE int common_enumset_string(const ObExpr &enumset_expr, + const uint64_t in_val, + ObEvalCtx &ctx, + ObTextStringResult &text_result) +{ + int ret = OB_SUCCESS; + const ObEnumSetMeta *meta = NULL; + const ObObjType in_type = enumset_expr.datum_meta_.type_; + if (0 == in_val) { + // empty string, do nothing + } else if (OB_FAIL(get_enumset_meta(ctx, enumset_expr.obj_meta_, meta))) { + LOG_WARN("fail to get enumset meta", K(ret)); + } else if (ObEnumType == in_type) { + ret = ObExprEnumToStr::inner_to_str(in_val, *meta->get_str_values(), text_result); + } else if (ObSetType == in_type) { + ret = ObExprSetToStr::inner_to_str(enumset_expr.datum_meta_.cs_type_, in_val, + *meta->get_str_values(), text_result); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected expr type", K(ret), K(in_type)); + } + return ret; +} + static int get_text_full_data(const sql::ObExpr &expr, sql::ObEvalCtx &ctx, ObIAllocator *allocator, @@ -3939,12 +3977,12 @@ CAST_FUNC_NAME(string, decimalint) } static int common_string_json(const ObExpr &expr, + const ObObjType in_type, const ObString &in_str, ObEvalCtx &ctx, ObDatum &res_datum) { int ret = OB_SUCCESS; - ObObjType in_type = expr.args_[0]->datum_meta_.type_; ObObjType out_type = ObLongTextType; ObCollationType in_cs_type = expr.args_[0]->datum_meta_.cs_type_; ObCollationType out_cs_type = expr.datum_meta_.cs_type_; @@ -3971,7 +4009,8 @@ static int common_string_json(const ObExpr &expr, j_text.assign_ptr(in_str.ptr(), in_str.length()); } bool is_enumset_to_str = ((expr.args_[0]->type_ == T_FUN_SET_TO_STR) - || (expr.args_[0]->type_ == T_FUN_ENUM_TO_STR)); + || (expr.args_[0]->type_ == T_FUN_ENUM_TO_STR) + || ob_is_enum_or_set_type(expr.args_[0]->datum_meta_.type_)); ObIJsonBase *j_base = NULL; ObJsonOpaque j_opaque(j_text, in_type); ObJsonString j_string(j_text.ptr(), j_text.length()); @@ -4075,7 +4114,7 @@ CAST_FUNC_NAME(string, json) &ctx.exec_ctx_))) { LOG_WARN("fail to get real data.", K(ret), K(in_str)); } else { - ret = common_string_json(expr, in_str, ctx, res_datum); + ret = common_string_json(expr, expr.args_[0]->datum_meta_.type_, in_str, ctx, res_datum); } } } @@ -7094,6 +7133,137 @@ CAST_FUNC_NAME(enumset, decimalint) return ret; } +CAST_FUNC_NAME(enumset, datetime) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObExpr &enumset_expr = *expr.args_[0]; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObTextStringResult text_result(ObVarcharType, false, &temp_allocator); + ObString es_str; + if (OB_FAIL(common_enumset_string(enumset_expr, in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (OB_FAIL(common_string_datetime(expr, es_str, ctx, res_datum))) { + LOG_WARN("common_string_datetime failed", K(ret), K(es_str)); + } + } + return ret; +} + +CAST_FUNC_NAME(enumset, date) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObExpr &enumset_expr = *expr.args_[0]; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObTextStringResult text_result(ObVarcharType, false, &temp_allocator); + ObString es_str; + if (OB_FAIL(common_enumset_string(enumset_expr, in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (OB_FAIL(common_string_date(expr, es_str, res_datum))) { + LOG_WARN("common_string_date failed", K(ret), K(es_str)); + } + } + return ret; +} + +CAST_FUNC_NAME(enumset, time) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObExpr &enumset_expr = *expr.args_[0]; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObTextStringResult text_result(ObVarcharType, false, &temp_allocator); + ObString es_str; + if (OB_FAIL(common_enumset_string(enumset_expr, in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (OB_FAIL(common_string_time(expr, es_str, res_datum))) { + LOG_WARN("common_string_time failed", K(ret), K(es_str)); + } + } + return ret; +} + +CAST_FUNC_NAME(enumset, string) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObTextStringDatumResult text_result(expr.datum_meta_.type_, &expr, &ctx, &res_datum); + if (OB_FAIL(common_enumset_string(*expr.args_[0], in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else { + text_result.set_result(); + } + } + return ret; +} + +CAST_FUNC_NAME(enumset, text) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObExpr &enumset_expr = *expr.args_[0]; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObTextStringResult text_result(ObVarcharType, false, &temp_allocator); + ObString es_str; + if (OB_FAIL(common_enumset_string(enumset_expr, in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (OB_FAIL(common_string_text(expr, es_str, ctx, NULL, res_datum))) { + LOG_WARN("common_string_text failed", K(ret), K(es_str)); + } + } + return ret; +} + +CAST_FUNC_NAME(enumset, lob) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObExpr &enumset_expr = *expr.args_[0]; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObTextStringResult text_result(ObVarcharType, false, &temp_allocator); + ObString es_str; + if (OB_FAIL(common_enumset_string(enumset_expr, in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (OB_FAIL(common_string_lob(expr, es_str, ctx, NULL, res_datum))) { + LOG_WARN("common_string_lob failed", K(ret), K(es_str)); + } + } + return ret; +} + +CAST_FUNC_NAME(enumset, json) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObExpr &enumset_expr = *expr.args_[0]; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObTextStringResult text_result(ObVarcharType, false, &temp_allocator); + ObString es_str; + if (OB_FAIL(common_enumset_string(enumset_expr, in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data( + &temp_allocator, ObVarcharType, false, es_str, &ctx.exec_ctx_))) { + LOG_WARN("fail to get real data.", K(ret), K(es_str)); + } else if (OB_FAIL(common_string_json(expr, ObVarcharType, es_str, ctx, res_datum))) { + LOG_WARN("common_string_json failed", K(ret), K(es_str)); + } + } + return ret; +} + CAST_FUNC_NAME(enumset_inner, int) { EVAL_ARG() { @@ -7834,7 +8004,7 @@ CAST_FUNC_NAME(raw, json) EVAL_ARG() { ObString in_str(child_res->len_, child_res->ptr_); - ret = common_string_json(expr, in_str, ctx, res_datum); + ret = common_string_json(expr, expr.args_[0]->datum_meta_.type_, in_str, ctx, res_datum); } return ret; } @@ -8222,7 +8392,7 @@ CAST_FUNC_NAME(lob, json) { const ObLobLocator &lob_locator = child_res->get_lob_locator(); ObString in_str(lob_locator.payload_size_, lob_locator.get_payload_ptr()); - OZ(common_string_json(expr, in_str, ctx, res_datum)); + OZ(common_string_json(expr, expr.args_[0]->datum_meta_.type_, in_str, ctx, res_datum)); } return ret; } @@ -10382,7 +10552,7 @@ int string_to_enum(ObIAllocator &alloc, uint64_t &output_value) { int ret = OB_SUCCESS; - const ObCollationType cs_type = expr.obj_meta_.get_collation_type(); + const ObCollationType cs_type = expr.datum_meta_.cs_type_; uint64_t value = 0; int32_t pos = 0; ObString in_str; @@ -10468,7 +10638,7 @@ int string_to_set(ObIAllocator &alloc, int ret = OB_SUCCESS; uint64_t value = 0; ObString in_str; - const ObCollationType cs_type = expr.obj_meta_.get_collation_type(); + const ObCollationType cs_type = expr.datum_meta_.cs_type_; OZ(ObCharset::charset_convert(alloc, orig_in_str, in_cs_type, cs_type, in_str)); if (OB_FAIL(ret)) { } else if (in_str.empty()) { @@ -11250,6 +11420,38 @@ CAST_FUNC_NAME(roaringbitmap, roaringbitmap) return ret; } +CAST_FUNC_NAME(enumset, enumset) +{ + EVAL_ARG() { + const uint64_t in_val = child_res->get_enumset(); + ObExpr &enumset_expr = *expr.args_[0]; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObTextStringResult text_result(ObVarcharType, false, &temp_allocator); + ObString es_str; + const ObEnumSetMeta *meta = NULL; + if (OB_FAIL(common_enumset_string(enumset_expr, in_val, ctx, text_result))) { + LOG_WARN("common_enumset_string failed", K(ret), K(in_val)); + } else if (FALSE_IT(text_result.get_result_buffer(es_str))) { + } else if (OB_FAIL(get_enumset_meta(ctx, expr.obj_meta_, meta))) { + LOG_WARN("fail to get enumset meta", K(ret)); + } else { + int warning = 0; + uint64_t value = 0; + const ObCastMode cast_mode = expr.extra_; + if (ObEnumType == expr.datum_meta_.type_) { + ret = string_to_enum(temp_allocator, es_str, expr.args_[0]->datum_meta_.cs_type_, + *meta->get_str_values(), cast_mode, expr, warning, value); + SET_RES_ENUM(value); + } else { + ret = string_to_set(temp_allocator, es_str, expr.args_[0]->datum_meta_.cs_type_, + *meta->get_str_values(), cast_mode, expr, warning, value); + SET_RES_SET(value); + } + } + } + return ret; +} // exclude varchar/char type int anytype_anytype_explicit(const sql::ObExpr &expr, sql::ObEvalCtx &ctx, @@ -14744,24 +14946,24 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = enumset_float, // /*float*/ enumset_double, // /*double*/ enumset_number, // /*number*/ - cast_not_expected,/*datetime*/ - cast_not_expected,/*date*/ - cast_not_expected,/*time*/ + enumset_datetime,/*datetime*/ + enumset_date,/*date*/ + enumset_time,/*time*/ enumset_year, // /*year*/ - cast_not_expected,/*string*/ + enumset_string,/*string*/ cast_not_support,/*extend*/ cast_not_support,/*unknown*/ - cast_not_expected,/*text*/ + enumset_text,/*text*/ enumset_bit, // /*bit*/ - cast_not_expected,/*enumset*/ + enumset_enumset, /*enumset*/ cast_not_expected,/*enumset_inner*/ cast_not_support,/*otimestamp*/ cast_inconsistent_types,/*raw*/ cast_not_expected,/*interval*/ cast_not_expected,/*rowid*/ - cast_not_expected,/*lob*/ - cast_not_expected,/*json*/ - cast_not_expected,/*geometry*/ + enumset_lob,/*lob*/ + enumset_json,/*json*/ + cast_not_support,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ enumset_decimalint,/*decimalint*/ cast_not_expected,/*collection, not implemented in mysql mode*/ diff --git a/src/sql/engine/expr/ob_expr_cast.cpp b/src/sql/engine/expr/ob_expr_cast.cpp index d35d4d0ca..88dc359bc 100644 --- a/src/sql/engine/expr/ob_expr_cast.cpp +++ b/src/sql/engine/expr/ob_expr_cast.cpp @@ -437,8 +437,9 @@ int ObExprCast::calc_result_type2(ObExprResType &type, ObCollationType collation_nation = session->get_nls_collation_nation(); type1.set_calc_type(get_calc_cast_type(type1.get_type(), dst_type.get_type())); int32_t length = 0; - if (ob_is_string_or_lob_type(dst_type.get_type()) || ob_is_raw(dst_type.get_type()) || ob_is_json(dst_type.get_type()) - || ob_is_geometry(dst_type.get_type())) { + if (ob_is_string_or_lob_type(dst_type.get_type()) || ob_is_raw(dst_type.get_type()) + || ob_is_json(dst_type.get_type()) + || ob_is_geometry(dst_type.get_type())) { type.set_collation_level(dst_type.get_collation_level()); int32_t len = dst_type.get_length(); int16_t length_semantics = ((dst_type.is_string_or_lob_locator_type() || dst_type.is_json()) @@ -557,15 +558,19 @@ int ObExprCast::calc_result_type2(ObExprResType &type, sql_xml_type.set_sql_udt(ObXMLSqlType); type1.set_calc_meta(sql_xml_type.get_obj_meta()); } else { - bool need_warp = false; + bool need_wrap = false; if (ob_is_enumset_tc(type1.get_type())) { // For enum/set type, need to check whether warp to string is required. - if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(type1.get_type(), type1.get_calc_type(), - false, need_warp))) { + if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(type1, type1.get_calc_type(), + false, need_wrap))) { LOG_WARN("need_wrap_to_string failed", K(ret), K(type1)); + } else if (!need_wrap) { + // need_wrap is false, set calc_type to type1 itself. + type1.set_calc_meta(type1.get_obj_meta()); + type1.set_calc_accuracy(type1.get_calc_accuracy()); } - } else if (OB_LIKELY(need_warp)) { - // need_warp is true, no-op and keep type1's calc_type is dst_type. It will be wrapped + } else if (OB_LIKELY(need_wrap)) { + // need_wrap is true, no-op and keep type1's calc_type is dst_type. It will be wrapped // to string in ObRawExprWrapEnumSet::visit(ObSysFunRawExpr &expr) later. } else { if (ob_is_geometry_tc(dst_type.get_type())) { @@ -581,7 +586,7 @@ int ObExprCast::calc_result_type2(ObExprResType &type, } } if (OB_SUCC(ret)) { - // need_warp is false, set calc_type to type1 itself. + // need_wrap is false, set calc_type to type1 itself. type1.set_calc_meta(type1.get_obj_meta()); } } diff --git a/src/sql/engine/expr/ob_expr_coalesce.cpp b/src/sql/engine/expr/ob_expr_coalesce.cpp index 7c6026b47..80cbe57fb 100644 --- a/src/sql/engine/expr/ob_expr_coalesce.cpp +++ b/src/sql/engine/expr/ob_expr_coalesce.cpp @@ -62,18 +62,22 @@ int ObExprCoalesce::calc_result_typeN(ObExprResType &type, LOG_WARN("cast basic session to sql session info failed", K(ret)); } else { ObExprOperator::calc_result_flagN(type, types, param_num); - ObObjType calc_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[type.get_type()]]; bool is_expr_integer_type = (ob_is_int_tc(type.get_type()) || ob_is_uint_tc(type.get_type())); bool all_null_type = true; for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { all_null_type = (types[i].get_type() != ObNullType) ? false : all_null_type; if (ob_is_enumset_tc(types[i].get_type())) { + ObObjType calc_type = get_enumset_calc_type(type.get_type(), i); if (OB_UNLIKELY(ObMaxType == calc_type)) { ret = OB_ERR_UNEXPECTED; SQL_ENG_LOG(WARN, "invalid type of parameter ", K(i), K(ret)); } else { types[i].set_calc_type(calc_type); + if (ob_is_string_type(calc_type)) { + types[i].set_calc_collation_type(type.get_collation_type()); + types[i].set_calc_collation_level(CS_LEVEL_IMPLICIT); + } } } else { bool is_arg_integer_type = (ob_is_int_tc(types[i].get_type()) || diff --git a/src/sql/engine/expr/ob_expr_column_conv.cpp b/src/sql/engine/expr/ob_expr_column_conv.cpp index d0103bdbf..8b9a7b62d 100644 --- a/src/sql/engine/expr/ob_expr_column_conv.cpp +++ b/src/sql/engine/expr/ob_expr_column_conv.cpp @@ -272,21 +272,12 @@ int ObExprColumnConv::calc_result_typeN(ObExprResType &type, type.set_result_flag(NOT_NULL_FLAG | NOT_NULL_WRITE_FLAG); } - bool enumset_to_varchar = false; - //here will wrap type_to_str if necessary - if (OB_SUCC(ret) && ob_is_enumset_tc(types[4].get_type())) { - ObObjType calc_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[types[0].get_type()]]; - if (OB_UNLIKELY(ObMaxType == calc_type)) { - ret = OB_ERR_UNEXPECTED; - SQL_ENG_LOG(WARN, "invalid type of parameter ", K(types[4]), K(types), K(ret)); - } else if (ObVarcharType == calc_type) { - enumset_to_varchar = true; - types[4].set_calc_type(calc_type); - types[4].set_calc_collation_type(coll_type); - types[4].set_calc_collation_level(CS_LEVEL_IMPLICIT); - type_ctx.set_cast_mode(type_ctx.get_cast_mode() | type_ctx.get_raw_expr()->get_extra()); - } + bool wrap_to_str = false; + if (OB_SUCC(ret) && OB_FAIL(calc_enum_set_result_type(type, types, coll_type, type_ctx, + wrap_to_str))) { + LOG_WARN("fail to calc enum set result type", K(ret)); } + // for table modify in oracle mode, we ignore charset convert failed if (OB_SUCC(ret) && lib::is_oracle_mode()) { type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_CHARSET_CONVERT_IGNORE_ERR); @@ -298,7 +289,7 @@ int ObExprColumnConv::calc_result_typeN(ObExprResType &type, LOG_WARN("failed to check valid implicit convert", K(ret)); } - if (OB_SUCC(ret) && !enumset_to_varchar) { + if (OB_SUCC(ret) && !wrap_to_str) { //cast type when type not same. const ObObjTypeClass value_tc = ob_obj_type_class(types[4].get_type()); const ObObjTypeClass type_tc = ob_obj_type_class(types[0].get_type()); @@ -325,7 +316,70 @@ int ObExprColumnConv::calc_result_typeN(ObExprResType &type, } } } - LOG_DEBUG("finish calc_result_typeN", K(type), K(types[4]), K(types[0]), K(enumset_to_varchar)); + LOG_DEBUG("finish calc_result_typeN", K(type), K(types[4]), K(types[0]), K(wrap_to_str)); + } + return ret; +} + +int ObExprColumnConv::calc_enum_set_result_type(ObExprResType &type, + ObExprResType *types, + ObCollationType coll_type, + ObExprTypeCtx &type_ctx, + bool &wrap_to_str) const +{ + int ret = OB_SUCCESS; + // here will wrap type_to_str if necessary + // for enum set type with subschema, it can directly execute any type of cast, + // so there is no need to wrap type_to_str. + if (ob_is_enumset_tc(types[4].get_type())) { + ObObjType calc_type = get_enumset_calc_type(types[0].get_type(), 4); + // When the types are inconsistent or it doesn't support enum/set type with subschema, + // new cast expression is required. + const bool support_enum_set_type_subschema = is_enum_set_with_subschema_arg(4); + bool need_add_cast = type.get_type() != types[4].get_type() || !support_enum_set_type_subschema; + // keep old behavior use session collation + coll_type = support_enum_set_type_subschema ? types[1].get_collation_type() : coll_type; + if (OB_UNLIKELY(ObMaxType == calc_type)) { + ret = OB_ERR_UNEXPECTED; + SQL_ENG_LOG(WARN, "invalid type of parameter ", K(types[4]), K(types), K(ret)); + } else if (ob_is_string_type(calc_type) && need_add_cast) { + wrap_to_str = true; + } else if (!need_add_cast && ob_is_enum_or_set_type(type.get_type())) { + wrap_to_str = true; // set wrap to str to true first + // the src and dst types are the same, and both are enum/set. we need to check the + // subschema id of the expr result type. + const ObRawExpr *conv_expr = get_raw_expr(); + const ObRawExpr *enumset_expr = NULL; + const ObEnumSetMeta *src_meta = NULL; + const ObExecContext *exec_ctx = NULL; + if (OB_ISNULL(conv_expr) || OB_ISNULL(enumset_expr = conv_expr->get_param_expr(4))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("raw expr or child expr is null", K(ret), KP(conv_expr)); + } else if (OB_ISNULL(exec_ctx = type_ctx.get_session()->get_cur_exec_ctx())) { + } else if (OB_UNLIKELY(!enumset_expr->is_enum_set_with_subschema())) { + // skip check enum/set expr with old behavior + } else if (OB_UNLIKELY(conv_expr->get_enum_set_values().empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("str values for enum set expr is empty", K(ret)); + } else if (OB_FAIL(exec_ctx->get_enumset_meta_by_subschema_id( + enumset_expr->get_subschema_id(), src_meta))) { + LOG_WARN("failed to meta from exec_ctx", K(ret), K(enumset_expr->get_subschema_id())); + } else if (OB_ISNULL(src_meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("src meta is unexpected", K(ret), KP(src_meta)); + } else if (src_meta->is_same(src_meta->get_obj_meta(), conv_expr->get_enum_set_values())) { + // set wrap to str to false, it will be checked in `ObRawExprWrapEnumSet` + wrap_to_str = false; + } + } + if (OB_SUCC(ret)) { + if (wrap_to_str) { + types[4].set_calc_type(calc_type); + types[4].set_calc_collation_type(coll_type); + types[4].set_calc_collation_level(CS_LEVEL_IMPLICIT); + type_ctx.set_cast_mode(type_ctx.get_cast_mode() | type_ctx.get_raw_expr()->get_extra()); + } + } } return ret; } diff --git a/src/sql/engine/expr/ob_expr_column_conv.h b/src/sql/engine/expr/ob_expr_column_conv.h index b359b10a3..5ef894b9c 100644 --- a/src/sql/engine/expr/ob_expr_column_conv.h +++ b/src/sql/engine/expr/ob_expr_column_conv.h @@ -150,6 +150,11 @@ public: { return ob_is_enum_or_set_type(result_type_.get_type()); } private: + int calc_enum_set_result_type(ObExprResType &type, + ObExprResType *types, + ObCollationType coll_type, + common::ObExprTypeCtx &type_ctx, + bool &wrap_to_str) const; static int eval_enumset(const ObExpr &expr, ObEvalCtx &ctx, common::ObDatum *&datum); private: diff --git a/src/sql/engine/expr/ob_expr_day_of_func.cpp b/src/sql/engine/expr/ob_expr_day_of_func.cpp index 7c8ab705a..62f52c2f1 100644 --- a/src/sql/engine/expr/ob_expr_day_of_func.cpp +++ b/src/sql/engine/expr/ob_expr_day_of_func.cpp @@ -346,7 +346,7 @@ int ObExprSubAddtime::calc_result_type2(ObExprResType &type, date_arg.set_calc_type(ObVarcharType); } if (ob_is_enumset_tc(time_arg.get_type())) { - time_arg.set_calc_type(ObVarcharType); + time_arg.set_calc_type(get_enumset_calc_type(ObTimeType, 1)); } else { type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NULL_ON_WARN); time_arg.set_calc_type(ObTimeType); diff --git a/src/sql/engine/expr/ob_expr_lob_utils.h b/src/sql/engine/expr/ob_expr_lob_utils.h index 875c9c516..294bd5954 100644 --- a/src/sql/engine/expr/ob_expr_lob_utils.h +++ b/src/sql/engine/expr/ob_expr_lob_utils.h @@ -43,7 +43,7 @@ public: TO_STRING_KV(KP_(expr), KP_(ctx), KPC_(res_datum)); - int init(int64_t res_len, ObIAllocator *allocator = NULL); + int init(int64_t res_len, ObIAllocator *allocator = NULL) override; int init_with_batch_idx(int64_t res_len, int64_t batch_idx); void set_result(); void set_result_null(); @@ -142,7 +142,7 @@ public: ~ObTextStringObObjResult(){}; TO_STRING_KV(KP_(params), KP_(res_obj)); - int init(int64_t res_len, ObIAllocator *allocator = NULL); + int init(int64_t res_len, ObIAllocator *allocator = NULL) override; void set_result(); private: diff --git a/src/sql/engine/expr/ob_expr_nullif.cpp b/src/sql/engine/expr/ob_expr_nullif.cpp index 918615f28..b7cf0a0db 100644 --- a/src/sql/engine/expr/ob_expr_nullif.cpp +++ b/src/sql/engine/expr/ob_expr_nullif.cpp @@ -89,12 +89,12 @@ int ObExprNullif::se_deduce_type(ObExprResType &type, OZ(calc_cmp_type2(cmp_type, type1, type2, type_ctx)); if (OB_SUCC(ret)) { if (ob_is_enumset_tc(type1.get_type()) || ob_is_enumset_tc(type2.get_type())) { - ObObjType calc_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[cmp_type.get_calc_type()]]; + ObObjType calc_type = get_enumset_calc_type(cmp_type.get_calc_type(), -1); CK(ObMaxType != calc_type); if (OB_SUCC(ret)) { cmp_type.set_calc_type(calc_type); cmp_type.set_calc_collation_type(ObCharset::get_system_collation()); - if (ObVarcharType == calc_type) { + if (ob_is_string_type(calc_type)) { if (ob_is_enumset_tc(type1.get_type())) { // only set calc type when calc_type is varchar. // EnumWrapper will add EnumToStr when calc_type is varchar, and otherwise add EnumToInner. @@ -108,7 +108,7 @@ int ObExprNullif::se_deduce_type(ObExprResType &type, if (type1.is_decimal_int()) { type1.set_calc_type(calc_type); } - // set calc type for type2 no matter whether calc_type is varchar or not, and no matther which param is enum. + // set calc type for type2 no matter whether calc_type is varchar or not, and no matter which param is enum. type2.set_calc_type(calc_type); type2.set_calc_collation_type(cmp_type.get_calc_collation_type()); type2.set_calc_collation_level(cmp_type.get_calc_collation_level()); diff --git a/src/sql/engine/expr/ob_expr_nvl.cpp b/src/sql/engine/expr/ob_expr_nvl.cpp index 049871bd5..406a0a89a 100644 --- a/src/sql/engine/expr/ob_expr_nvl.cpp +++ b/src/sql/engine/expr/ob_expr_nvl.cpp @@ -179,19 +179,20 @@ int ObExprNvl::calc_result_type2(ObExprResType &type, const bool type1_is_enumset = ob_is_enumset_tc(type1.get_type()); const bool type2_is_enumset = ob_is_enumset_tc(type2.get_type()); if (type1_is_enumset || type2_is_enumset) { - ObObjType calc_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[type.get_type()]]; + ObObjType calc_type = get_enumset_calc_type(type.get_type(), OB_INVALID_INDEX); if (OB_UNLIKELY(ObMaxType == calc_type)) { ret = OB_ERR_UNEXPECTED; SQL_ENG_LOG(WARN, "invalid type of parameter ", K(type1), K(type2), K(ret)); } else if (ObVarcharType == calc_type) { if (type1_is_enumset) { - type1.set_calc_type(calc_type); - type1.set_calc_collation_type(ObCharset::get_system_collation()); + type1.set_calc_type(get_enumset_calc_type(type.get_type(), 0)); + type1.set_calc_collation_type(type.get_collation_type()); } else { set_calc_type(type, type1); } if (type2_is_enumset) { - type2.set_calc_type(calc_type); + type2.set_calc_type(get_enumset_calc_type(type.get_type(), 1)); + type2.set_calc_collation_type(type.get_collation_type()); } else { set_calc_type(type, type2); } diff --git a/src/sql/engine/expr/ob_expr_operator.cpp b/src/sql/engine/expr/ob_expr_operator.cpp index f73871649..cede1f2a9 100644 --- a/src/sql/engine/expr/ob_expr_operator.cpp +++ b/src/sql/engine/expr/ob_expr_operator.cpp @@ -865,7 +865,7 @@ int ObExprOperator::aggregate_charsets_for_string_result( if (OB_FAIL(enable_old_charset_aggregation(type_ctx.get_session(), flags))) { LOG_WARN("failed to check is_old_charset_aggregation_enabled", K(ret)); } else { - ret = aggregate_charsets(type, types, param_num, flags, type_ctx.get_coll_type()); + ret = aggregate_charsets(type, types, param_num, flags, type_ctx); } return ret; } @@ -883,7 +883,7 @@ int ObExprOperator::aggregate_charsets_for_string_result( if (OB_FAIL(enable_old_charset_aggregation(type_ctx.get_session(), flags))) { LOG_WARN("failed to check is_old_charset_aggregation_enabled", K(ret)); } else { - ret = aggregate_charsets(type, types, param_num, flags, type_ctx.get_coll_type()); + ret = aggregate_charsets(type, types, param_num, flags, type_ctx); } return ret; } @@ -901,7 +901,7 @@ int ObExprOperator::aggregate_charsets_for_comparison( if (OB_FAIL(enable_old_charset_aggregation(type_ctx.get_session(), flags))) { LOG_WARN("failed to check is_old_charset_aggregation_enabled", K(ret)); } else { - ret = aggregate_charsets(type, types, param_num, flags, type_ctx.get_coll_type()); + ret = aggregate_charsets(type, types, param_num, flags, type_ctx); } return ret; } @@ -920,7 +920,7 @@ int ObExprOperator::aggregate_charsets_for_comparison( if (OB_FAIL(enable_old_charset_aggregation(type_ctx.get_session(), flags))) { LOG_WARN("failed to check is_old_charset_aggregation_enabled", K(ret)); } else { - ret = aggregate_charsets(type.get_calc_meta(), types, param_num, flags, type_ctx.get_coll_type()); + ret = aggregate_charsets(type.get_calc_meta(), types, param_num, flags, type_ctx); } return ret; } @@ -939,7 +939,7 @@ int ObExprOperator::aggregate_charsets_for_string_result_with_comparison( if (OB_FAIL(enable_old_charset_aggregation(type_ctx.get_session(), flags))) { LOG_WARN("failed to check is_old_charset_aggregation_enabled", K(ret)); } else { - ret = aggregate_charsets(type, types, param_num, flags, type_ctx.get_coll_type()); + ret = aggregate_charsets(type, types, param_num, flags, type_ctx); } return ret; } @@ -958,7 +958,7 @@ int ObExprOperator::aggregate_charsets_for_string_result_with_comparison( if (OB_FAIL(enable_old_charset_aggregation(type_ctx.get_session(), flags))) { LOG_WARN("failed to check is_old_charset_aggregation_enabled", K(ret)); } else { - ret = aggregate_charsets(type, types, param_num, flags, type_ctx.get_coll_type()); + ret = aggregate_charsets(type, types, param_num, flags, type_ctx); } return ret; } @@ -968,9 +968,9 @@ int ObExprOperator::aggregate_charsets( const ObObjMeta *types, int64_t param_num, uint32_t flags, - const ObCollationType conn_coll_type) + common::ObExprTypeCtx &type_ctx) { - return aggregate_collations(type, types, param_num, flags, conn_coll_type); + return aggregate_collations(type, types, param_num, flags, type_ctx.get_coll_type()); } int ObExprOperator::aggregate_charsets( @@ -978,7 +978,7 @@ int ObExprOperator::aggregate_charsets( const ObExprResType *types, int64_t param_num, uint32_t flags, - const ObCollationType conn_coll_type) + common::ObExprTypeCtx &type_ctx) { int ret = OB_SUCCESS; CK(OB_NOT_NULL(types), @@ -990,20 +990,30 @@ int ObExprOperator::aggregate_charsets( for (int i = 0; OB_SUCC(ret) && i < param_num; ++i) { coll.reset(); // issue:49962420 The xml type calls get_collation_type() to return the result of binary, here is set to utf8 + coll.set_collation_level(types[i].get_collation_level()); if (type.is_string_type() && types[i].is_xml_sql_type()) { coll.set_collation_type(ObCollationType::CS_TYPE_UTF8MB4_BIN); + } else if (types[i].is_enum_set_with_subschema()) { + ObObjMeta obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(types[i], type_ctx.get_session(), + obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + coll.set_collation(obj_meta); + } } else { coll.set_collation_type(types[i].get_collation_type()); } - coll.set_collation_level(types[i].get_collation_level()); - ret = coll_types.push_back(coll); + if (OB_SUCC(ret)) { + ret = coll_types.push_back(coll); + } } // end for OZ (aggregate_charsets(type, &coll_types.at(0), param_num, flags, - conn_coll_type)); + type_ctx)); } return ret; } @@ -1273,9 +1283,9 @@ int ObExprOperator::aggregate_result_type_for_case( if (OB_FAIL(aggregate_numeric_accuracy_for_merge(type, types, param_num, is_oracle_mode))) { LOG_WARN("fail to aggregate numeric accuracy", K(ret)); } - } else if (OB_FAIL(aggregate_result_type_for_merge(type, types, param_num, - is_oracle_mode, type_ctx, need_merge_type, skip_null, - is_called_in_sql))) { + // the collation of case_expr has been restored + } else if (OB_FAIL(aggregate_result_type_for_merge(type, types, param_num, is_oracle_mode, + type_ctx, need_merge_type, skip_null, is_called_in_sql))) { LOG_WARN("fail to aggregate result type", K(ret)); } else if (ObFloatType == type.get_type() && !is_oracle_mode) { type.set_type(ObDoubleType); @@ -1309,6 +1319,7 @@ int ObExprOperator::aggregate_result_type_for_merge( const ObLengthSemantics default_length_semantics = ((OB_NOT_NULL(type_ctx.get_session())) ? type_ctx.get_session()->get_actual_nls_length_semantics() : LS_BYTE); + bool has_new_enum_set_type = types[0].is_enum_set_with_subschema(); for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) { if (OB_FAIL(ObExprResultTypeUtil::get_merge_result_type(res_type, res_type, @@ -1327,6 +1338,8 @@ int ObExprOperator::aggregate_result_type_for_merge( types[i].get_precision() == types[i-1].get_precision() && types[i].get_scale() == types[i-1].get_scale(); } + } else if (types[i].is_enum_set_with_subschema()) { + has_new_enum_set_type = true; } } if (OB_SUCC(ret)) { @@ -1345,8 +1358,32 @@ int ObExprOperator::aggregate_result_type_for_merge( } else if (ob_is_temporal_type(res_type) || ob_is_otimestamp_type(res_type)) { ret = aggregate_temporal_accuracy_for_merge(type, types, param_num); } else if (ob_is_string_or_lob_type(res_type)) { - if (OB_FAIL(aggregate_charsets_for_string_result(type, types, param_num, type_ctx))) { - } else if (OB_FAIL(aggregate_max_length_for_string_result(type, types, param_num, + const ObExprResType *new_types = types; + const ObSQLSessionInfo *session_info = type_ctx.get_session(); + if (has_new_enum_set_type && session_info != NULL) { + ObSEArray restored_types; + for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { + if (OB_FAIL(restored_types.push_back(types[i]))) { + LOG_WARN("fail to push back types", K(ret)); + } else if (types[i].is_enum_set_with_subschema()) { + ObObjMeta obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(types[i], session_info, + obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + restored_types[i].set_collation(obj_meta); + restored_types[i].reset_enum_set_meta_state(); + } + } + } + if (OB_SUCC(ret)) { + new_types = &restored_types.at(0); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(aggregate_charsets_for_string_result(type, new_types, param_num, + type_ctx))) { + } else if (OB_FAIL(aggregate_max_length_for_string_result(type, new_types, param_num, is_oracle_mode, default_length_semantics, need_merge_type, skip_null, is_called_in_sql))) { } else {/*do nothing*/} @@ -1770,38 +1807,72 @@ int ObExprDFMConvertCtx::parse_format(const ObString &format_str, ObExprFindIntCachedValue::~ObExprFindIntCachedValue() { } -ObObjType ObExprOperator::enumset_calc_types_[ObMaxTC] = +ObObjType ObExprOperator::enumset_calc_types_[2 /*use_subschema*/][ObMaxTC] = { - ObUInt64Type,/*ObNullTC*/ - ObUInt64Type,/*ObIntTC*/ - ObUInt64Type,/*ObUIntTC*/ - ObUInt64Type,/*ObFloatTC*/ - ObUInt64Type,/*ObDoubleTC*/ - ObUInt64Type,/*ObNumberTC*/ - ObVarcharType,/*ObDateTimeTC*/ - ObVarcharType,/*ObDateTC*/ - ObVarcharType,/*ObTimeTC*/ - ObUInt64Type,/*ObYearTC*/ - ObVarcharType,/*ObStringTC*/ - ObMaxType,/*ObExtendTC*/ - ObMaxType,/*ObUnknownTC*/ - ObVarcharType,/*ObTextTC*/ - ObUInt64Type,/*ObBitTC*/ - ObVarcharType,/*ObEnumSetTC*/ - ObVarcharType,/*ObEnumSetInnerTC*/ - ObVarcharType, /*ObOTimestampTC*/ - ObNullType, /*ObRawTC*/ - ObVarcharType, /*ObInternalTC*/ - ObVarcharType, /*ObRowIDTC*/ - ObMaxType, /*ObLobTC*/ - ObVarcharType, /*ObJsonTC*/ - ObVarcharType, /*ObGeometryTC*/ - ObNullType, /*UDT*/ - ObUInt64Type, /*ObDecimalIntTC*/ - ObNullType, /*COLLECTION*/ - ObVarcharType, /*ObMySQLDateTC*/ - ObVarcharType, /*ObMySQLDateTimeTC*/ - ObVarcharType, /*ObRoaringBitmapTC*/ + { + ObUInt64Type,/*ObNullTC*/ + ObUInt64Type,/*ObIntTC*/ + ObUInt64Type,/*ObUIntTC*/ + ObUInt64Type,/*ObFloatTC*/ + ObUInt64Type,/*ObDoubleTC*/ + ObUInt64Type,/*ObNumberTC*/ + ObVarcharType,/*ObDateTimeTC*/ + ObVarcharType,/*ObDateTC*/ + ObVarcharType,/*ObTimeTC*/ + ObUInt64Type,/*ObYearTC*/ + ObVarcharType,/*ObStringTC*/ + ObMaxType,/*ObExtendTC*/ + ObMaxType,/*ObUnknownTC*/ + ObVarcharType,/*ObTextTC*/ + ObUInt64Type,/*ObBitTC*/ + ObVarcharType,/*ObEnumSetTC*/ + ObVarcharType,/*ObEnumSetInnerTC*/ + ObVarcharType, /*ObOTimestampTC*/ + ObNullType, /*ObRawTC*/ + ObVarcharType, /*ObInternalTC*/ + ObVarcharType, /*ObRowIDTC*/ + ObMaxType, /*ObLobTC*/ + ObVarcharType, /*ObJsonTC*/ + ObVarcharType, /*ObGeometryTC*/ + ObNullType, /*UDT*/ + ObUInt64Type, /*ObDecimalIntTC*/ + ObNullType, /*COLLECTION*/ + ObVarcharType, /*ObMySQLDateTC*/ + ObVarcharType, /*ObMySQLDateTimeTC*/ + ObVarcharType, /*ObRoaringBitmapTC*/ + }, + { + ObUInt64Type,/*ObNullTC*/ + ObUInt64Type,/*ObIntTC*/ + ObUInt64Type,/*ObUIntTC*/ + ObUInt64Type,/*ObFloatTC*/ + ObUInt64Type,/*ObDoubleTC*/ + ObUInt64Type,/*ObNumberTC*/ + ObDateTimeType,/*ObDateTimeTC*/ + ObDateType,/*ObDateTC*/ + ObTimeType,/*ObTimeTC*/ + ObUInt64Type,/*ObYearTC*/ + ObVarcharType,/*ObStringTC*/ + ObMaxType,/*ObExtendTC*/ + ObMaxType,/*ObUnknownTC*/ + ObVarcharType,/*ObTextTC*/ + ObUInt64Type,/*ObBitTC*/ + ObVarcharType,/*ObEnumSetTC*/ + ObVarcharType,/*ObEnumSetInnerTC*/ + ObVarcharType, /*ObOTimestampTC*/ + ObNullType, /*ObRawTC*/ + ObVarcharType, /*ObInternalTC*/ + ObVarcharType, /*ObRowIDTC*/ + ObMaxType, /*ObLobTC*/ + ObJsonType, /*ObJsonTC*/ + ObVarcharType, /*ObGeometryTC*/ + ObNullType, /*UDT*/ + ObUInt64Type, /*ObDecimalIntTC*/ + ObNullType, /*COLLECTION*/ + ObMaxType, /*ObMySQLDateTC*/ + ObMaxType, /*ObMySQLDateTimeTC*/ + ObVarcharType, /*ObRoaringBitmapTC*/ + }, }; //////////////////////////////////////////////////////////////// @@ -2556,6 +2627,34 @@ int ObExprOperator::add_local_var_to_expr(ObSysVarClassType var_type, return ret; } +bool ObExprOperator::is_enum_set_with_subschema_arg(const int64_t arg_idx) const +{ + bool bret = false; + const ObRawExpr *arg_expr = NULL; + if (arg_idx >= 0 && OB_NOT_NULL(raw_expr_) && arg_idx < raw_expr_->get_param_count() + && OB_NOT_NULL(arg_expr = raw_expr_->get_param_expr(arg_idx)) + && arg_expr->is_enum_set_with_subschema()) { + bret = true; + } + return bret; +} + +ObObjType ObExprOperator::get_enumset_calc_type(const ObObjType expected_type, + const int64_t arg_idx) const +{ + ObObjType calc_type = ObMaxType; + if (is_enum_set_with_subschema_arg(arg_idx)) { + calc_type = enumset_calc_types_[1 /*use subschema*/][OBJ_TYPE_TO_CLASS[expected_type]]; + // set calc type to dst type direct, otherwise multiple casts may occur. + if (ob_is_string_type(expected_type)) { + calc_type = expected_type; + } + } else { + calc_type = enumset_calc_types_[0 /*for compatibility*/][OBJ_TYPE_TO_CLASS[expected_type]]; + } + return calc_type; +} + OB_SERIALIZE_MEMBER(ObIterExprOperator, expr_id_, expr_type_); int ObRelationalExprOperator::calc_result_type2(ObExprResType &type, @@ -4978,6 +5077,26 @@ void ObStringExprOperator::calc_temporal_format_result_length(ObExprResType &typ type.set_length(default_text_length); } } +int ObStringExprOperator::extract_enum_set_collation_for_args(const ObExprResType &text, + const ObExprResType &pattern, + ObExprTypeCtx &type_ctx, + ObObjMeta *real_types) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret) && text.is_enum_set_with_subschema()) { + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(text, type_ctx.get_session(), + real_types[0]))) { + LOG_WARN("fail to extract enum set collation", K(ret)); + } + } + if (OB_SUCC(ret) && pattern.is_enum_set_with_subschema()) { + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(pattern, type_ctx.get_session(), + real_types[1]))) { + LOG_WARN("fail to extract enum set collation", K(ret)); + } + } + return ret; +} ObObjType ObStringExprOperator::get_result_type_mysql(int64_t char_length) const { @@ -5896,18 +6015,16 @@ int ObMinMaxExprOperator::calc_result_meta_for_comparison( } } - if (OB_SUCC(ret)) { - ObObjType dest_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[type.get_calc_type()]]; - if (OB_UNLIKELY(ObMaxType == dest_type)) { - ret = OB_ERR_UNEXPECTED; - SQL_ENG_LOG(WARN, "invalid type", K(type), K(ret)); - } else if (ObVarcharType == dest_type) { - for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { - if (ob_is_enumset_tc(types_stack[i].get_type())) { - types_stack[i].set_calc_type(dest_type); - } - } - } else {/*do nothing*/} + for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) { + if (ob_is_enumset_tc(types_stack[i].get_type())) { + ObObjType dest_type = get_enumset_calc_type(type.get_calc_type(), i); + if (OB_UNLIKELY(ObMaxType == dest_type)) { + ret = OB_ERR_UNEXPECTED; + SQL_ENG_LOG(WARN, "invalid type", K(type), K(ret)); + } else if (ob_is_string_type(dest_type)) { + types_stack[i].set_calc_type(dest_type); + } else {/*do nothing*/} + } } return ret; } diff --git a/src/sql/engine/expr/ob_expr_operator.h b/src/sql/engine/expr/ob_expr_operator.h index 1b23a763c..46fc33293 100644 --- a/src/sql/engine/expr/ob_expr_operator.h +++ b/src/sql/engine/expr/ob_expr_operator.h @@ -506,6 +506,8 @@ public: J_OBJ_END(); return pos; } + bool is_enum_set_with_subschema_arg(const int64_t arg_idx) const; + ObObjType get_enumset_calc_type(const ObObjType expected_type, const int64_t arg_idx) const; public: /* Aggregate arguments for comparison, e.g: a=b, a LIKE b, a RLIKE b @@ -705,10 +707,10 @@ protected: const ObExprResType *types, int64_t param_num); static common::ObObjType get_calc_cast_type(common::ObObjType param_type, common::ObObjType calc_type); - static common::ObObjType enumset_calc_types_[common::ObMaxTC]; void disable_operand_auto_cast() { operand_auto_cast_ = false; } private: + static common::ObObjType enumset_calc_types_[2 /*use_subschema*/][common::ObMaxTC]; /* * 计算框架本身提供了一个通用的数据类型转换方法,将参数转为input_types_中的类型。 * 这可能并不是表达式期望的行为,如需要禁止此行为,需要在构造函数中显示调 disable_operand_auto_cast(). @@ -739,14 +741,14 @@ protected: const common::ObObjMeta *types, int64_t param_num, uint32_t flags, - const common::ObCollationType conn_coll_type); + common::ObExprTypeCtx &type_ctx); static int aggregate_charsets( common::ObObjMeta &type, const ObExprResType *types, int64_t param_num, uint32_t flags, - const common::ObCollationType conn_coll_type); + common::ObExprTypeCtx &type_ctx); // data members @@ -1934,6 +1936,11 @@ public: common::ObObj &result, common::ObIAllocator *allocator); void calc_temporal_format_result_length(ObExprResType &type, const ObExprResType &format) const; +protected: + static int extract_enum_set_collation_for_args(const ObExprResType &text, + const ObExprResType &pattern, + ObExprTypeCtx &type_ctx, + ObObjMeta *real_types); protected: common::ObObjType get_result_type_mysql(int64_t char_length) const; static const int64_t MAX_CHAR_LENGTH_FOR_VARCAHR_RESULT = 512; diff --git a/src/sql/engine/expr/ob_expr_oracle_decode.cpp b/src/sql/engine/expr/ob_expr_oracle_decode.cpp index b333f9ca1..d2fec358f 100644 --- a/src/sql/engine/expr/ob_expr_oracle_decode.cpp +++ b/src/sql/engine/expr/ob_expr_oracle_decode.cpp @@ -251,7 +251,7 @@ int ObExprOracleDecode::calc_result_typeN(ObExprResType &type, } else { // 这里针对calc的转换是不是可以直接用在result上?? - result_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[type.get_type()]]; + result_type = get_enumset_calc_type(type.get_type(), OB_INVALID_INDEX); } if (OB_UNLIKELY(ObMaxType == result_type)) { ret = OB_ERR_UNEXPECTED; @@ -259,30 +259,30 @@ int ObExprOracleDecode::calc_result_typeN(ObExprResType &type, } else if (ObVarcharType == result_type) { for (int64_t i = 2; i < param_num; i += 2 /*skip conditions */) { if (types_stack[i].is_enum_or_set()) { - types_stack[i].set_calc_type(ObVarcharType); + types_stack[i].set_calc_type(get_enumset_calc_type(type.get_type(), i)); } } if (has_default) { if (types_stack[param_num - 1].is_enum_or_set()) { - types_stack[param_num - 1].set_calc_type(ObVarcharType); + types_stack[param_num - 1].set_calc_type(get_enumset_calc_type(type.get_type(), param_num - 1)); } } } } if (OB_SUCC(ret)) { - ObObjType calc_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[type.get_calc_type()]]; + ObObjType calc_type = get_enumset_calc_type(type.get_calc_type(), OB_INVALID_INDEX); if (OB_UNLIKELY(ObMaxType == calc_type)) { ret = OB_ERR_UNEXPECTED; SQL_ENG_LOG(WARN, "invalid type of parameter ", K(type), K(ret)); } else if (ObVarcharType == calc_type) { if (types_stack[0].is_enum_or_set()) { - types_stack[0].set_calc_type(ObVarcharType); + types_stack[0].set_calc_type(get_enumset_calc_type(type.get_calc_type(), 0)); } for (int64_t i = 1; i < param_num; i += 2 /*skip conditions */) { //here to let enumset wrapper knows if (types_stack[i].is_enum_or_set()) { - types_stack[i].set_calc_type(ObVarcharType); + types_stack[i].set_calc_type(get_enumset_calc_type(type.get_calc_type(), i)); } } } else {/*do nothing*/} diff --git a/src/sql/engine/expr/ob_expr_prior.cpp b/src/sql/engine/expr/ob_expr_prior.cpp index 7c592d006..3090d6a40 100644 --- a/src/sql/engine/expr/ob_expr_prior.cpp +++ b/src/sql/engine/expr/ob_expr_prior.cpp @@ -63,7 +63,7 @@ int ObExprPrior::calc_prior_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &re if (OB_ISNULL(kit) || OB_ISNULL(kit->op_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("operator is NULL", K(ret), K(operator_id), KP(kit)); - } else if (OB_UNLIKELY(PHY_NESTED_LOOP_CONNECT_BY != kit->op_->get_spec().type_ + } else if (OB_UNLIKELY(PHY_CONNECT_BY != kit->op_->get_spec().type_ && PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX != kit->op_->get_spec().type_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("is not connect by operator", K(ret), K(operator_id), "spec", kit->op_->get_spec()); @@ -71,7 +71,7 @@ int ObExprPrior::calc_prior_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &re LOG_WARN("failed to eval expr", K(ret)); } else { int64_t level = 0; - if (PHY_NESTED_LOOP_CONNECT_BY == kit->op_->get_spec().type_) { + if (PHY_CONNECT_BY == kit->op_->get_spec().type_) { ObNLConnectByOp *cnntby_op = static_cast(kit->op_); level = cnntby_op->connect_by_pump_.get_current_level(); } else { diff --git a/src/sql/engine/expr/ob_expr_regexp_replace.cpp b/src/sql/engine/expr/ob_expr_regexp_replace.cpp index a38892c1f..42db3359e 100644 --- a/src/sql/engine/expr/ob_expr_regexp_replace.cpp +++ b/src/sql/engine/expr/ob_expr_regexp_replace.cpp @@ -109,6 +109,8 @@ int ObExprRegexpReplace::calc_result_typeN(ObExprResType &type, type.set_length(max_allowed_packet); if (OB_FAIL(ObExprRegexContext::check_binary_compatible(types, 3))) { LOG_WARN("types are not compatible with binary.", K(ret)); + } else if (OB_FAIL(extract_enum_set_collation_for_args(text, pattern, type_ctx, real_types))) { + LOG_WARN("fail to extract enum set meta", K(ret)); } else { ret = aggregate_charsets_for_string_result(type, real_types, 2, type_ctx); is_case_sensitive = ObCharset::is_bin_sort(type.get_collation_type()); diff --git a/src/sql/engine/expr/ob_expr_regexp_substr.cpp b/src/sql/engine/expr/ob_expr_regexp_substr.cpp index 3b31eead1..763c9d49c 100644 --- a/src/sql/engine/expr/ob_expr_regexp_substr.cpp +++ b/src/sql/engine/expr/ob_expr_regexp_substr.cpp @@ -97,6 +97,8 @@ int ObExprRegexpSubstr::calc_result_typeN(ObExprResType &type, type.set_length(text.get_length()); if (OB_FAIL(ObExprRegexContext::check_binary_compatible(types, 2))) { LOG_WARN("types are not compatible with binary.", K(ret)); + } else if (OB_FAIL(extract_enum_set_collation_for_args(text, pattern, type_ctx, real_types))) { + LOG_WARN("fail to extract enum set meta", K(ret)); } else { ret = aggregate_charsets_for_string_result(type, real_types, 2, type_ctx); is_case_sensitive = ObCharset::is_bin_sort(type.get_collation_type()); diff --git a/src/sql/engine/expr/ob_expr_res_type.h b/src/sql/engine/expr/ob_expr_res_type.h index 915bfb3a5..f01f7f1af 100644 --- a/src/sql/engine/expr/ob_expr_res_type.h +++ b/src/sql/engine/expr/ob_expr_res_type.h @@ -23,6 +23,7 @@ #include "lib/utility/utility.h" #include "common/ob_accuracy.h" #include "common/object/ob_obj_type.h" +#include "lib/enumset/ob_enum_set_meta.h" namespace oceanbase { @@ -338,6 +339,16 @@ public: } uint64_t get_cast_mode() const { return cast_mode_; } + + OB_INLINE void mark_enum_set_with_subschema() + { + if (is_enum_or_set()) { + set_scale(ObEnumSetMeta::MetaState::READY); + } + } + OB_INLINE bool is_enum_set_with_subschema() const + { return is_enum_or_set() && get_scale() == ObEnumSetMeta::MetaState::READY; } + OB_INLINE void reset_enum_set_meta_state() { set_scale(ObEnumSetMeta::MetaState::UNINITIALIZED); } uint64_t hash(uint64_t seed) const { seed = common::do_hash(type_, seed); diff --git a/src/sql/engine/expr/ob_expr_statement_digest.cpp b/src/sql/engine/expr/ob_expr_statement_digest.cpp index a82d6bb8d..7f00a8288 100644 --- a/src/sql/engine/expr/ob_expr_statement_digest.cpp +++ b/src/sql/engine/expr/ob_expr_statement_digest.cpp @@ -30,6 +30,59 @@ namespace oceanbase namespace sql { +int calc_digest_text_inner(const ObString &query, + const int64_t i, + ObIAllocator &allocator, + ObPlanCacheCtx &pc_ctx, + ObParser &parser, + ObCharsets4Parser &charsets4parser, + ObString &digest_str) +{ + int ret = OB_SUCCESS; + ParseResult parse_result; + ParamStore tmp_params((ObWrapperAllocator(allocator))); + stmt::StmtType stmt_type = stmt::T_NONE; + ObItemType item_type = T_NULL; + if (OB_FAIL(parser.parse(query, parse_result))) { + LOG_WARN("fail to parse sql str", K(query), K(ret)); + } else if (OB_ISNULL(parse_result.result_tree_) + || OB_ISNULL(parse_result.result_tree_->children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected parse result", K(ret)); + } else if (FALSE_IT(item_type = parse_result.result_tree_->children_[0]->type_)) { + } else if (i > 0) { + if (OB_UNLIKELY(T_EMPTY_QUERY != item_type)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid stmt type", K(item_type), K(ret)); + LOG_USER_ERROR(OB_INVALID_ARGUMENT, "digest function"); + } + } else if (OB_UNLIKELY(T_EMPTY_QUERY == item_type)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid empty query", K(item_type), K(ret)); + LOG_USER_ERROR(OB_INVALID_ARGUMENT, "digest function"); + } else if (OB_FAIL(ObResolverUtils::resolve_stmt_type(parse_result, stmt_type))) { + LOG_WARN("failed to resolve stmt type", K(ret)); + } else if (ObStmt::is_dml_stmt(stmt_type) && !ObStmt::is_show_stmt(stmt_type)) { + if (OB_UNLIKELY(parse_result.result_tree_->children_[0]->value_ > 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("query contains questionmark", K(query), K(ret)); + LOG_USER_ERROR(OB_INVALID_ARGUMENT, "digest function"); + } else if (OB_FAIL(ObSqlParameterization::parameterize_syntax_tree(allocator, + true, + pc_ctx, + parse_result.result_tree_, + tmp_params, + charsets4parser))) { + LOG_WARN("fail to parameterize syntax tree", K(query), K(ret)); + } else { + digest_str = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.format_sql_; + } + } else { + digest_str = query; + } + return ret; +} + int calc_digest_text(ObIAllocator &allocator, const ObString sql_str, const ObCollationType cs_type, @@ -57,48 +110,12 @@ int calc_digest_text(ObIAllocator &allocator, ObMPParseStat parse_stat; if (OB_FAIL(parser.split_multiple_stmt(sql_str, queries, parse_stat))) { LOG_WARN("failed to split multiple stmt", K(ret)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < queries.count(); ++i) { - ParseResult parse_result; - ParamStore tmp_params((ObWrapperAllocator(allocator))); - stmt::StmtType stmt_type = stmt::T_NONE; - ObItemType item_type = T_NULL; - if (OB_FAIL(parser.parse(queries.at(i), parse_result))) { - LOG_WARN("fail to parse sql str", K(sql_str), K(ret)); - } else if (OB_ISNULL(parse_result.result_tree_) - || OB_ISNULL(parse_result.result_tree_->children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected parse result", K(ret)); - } else if (FALSE_IT(item_type = parse_result.result_tree_->children_[0]->type_)) { - } else if (i > 0) { - if (OB_UNLIKELY(T_EMPTY_QUERY != item_type)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid stmt type", K(item_type), K(ret)); - LOG_USER_ERROR(OB_INVALID_ARGUMENT, "digest function"); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < queries.count(); ++i) { + if (OB_FAIL(calc_digest_text_inner(queries.at(i), i, allocator, pc_ctx, parser, + charsets4parser, digest_str))) { + LOG_WARN("fail to calc digest test inner", K(ret), K(sql_str)); } - } else if (OB_UNLIKELY(T_EMPTY_QUERY == item_type)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid empty query", K(item_type), K(ret)); - LOG_USER_ERROR(OB_INVALID_ARGUMENT, "digest function"); - } else if (OB_FAIL(ObResolverUtils::resolve_stmt_type(parse_result, stmt_type))) { - LOG_WARN("failed to resolve stmt type", K(ret)); - } else if (ObStmt::is_dml_stmt(stmt_type) && !ObStmt::is_show_stmt(stmt_type)) { - if (OB_UNLIKELY(parse_result.result_tree_->children_[0]->value_ > 0)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("query contains questionmark", K(queries.at(i)), K(ret)); - LOG_USER_ERROR(OB_INVALID_ARGUMENT, "digest function"); - } else if (OB_FAIL(ObSqlParameterization::parameterize_syntax_tree(allocator, - true, - pc_ctx, - parse_result.result_tree_, - tmp_params, - charsets4parser))) { - LOG_WARN("fail to parameterize syntax tree", K(sql_str), K(ret)); - } else { - digest_str = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.format_sql_; - } - } else { - digest_str = queries.at(i); } } exec_ctx.set_physical_plan_ctx(NULL); diff --git a/src/sql/engine/expr/ob_expr_to_base64.cpp b/src/sql/engine/expr/ob_expr_to_base64.cpp index 908a9aa2a..9b62ddf74 100644 --- a/src/sql/engine/expr/ob_expr_to_base64.cpp +++ b/src/sql/engine/expr/ob_expr_to_base64.cpp @@ -74,7 +74,7 @@ int ObExprToBase64::calc_result_type1(ObExprResType &type, str.set_calc_type(ObVarcharType); str.set_calc_collation_type( - str.is_string_type() ? str.get_collation_type() : CS_TYPE_UTF8MB4_BIN); + (str.is_string_type() || str.is_enum_or_set()) ? str.get_collation_type() : CS_TYPE_UTF8MB4_BIN); int64_t mbmaxlen = 0; int64_t max_result_length = 0; diff --git a/src/sql/engine/expr/ob_expr_to_type.cpp b/src/sql/engine/expr/ob_expr_to_type.cpp index 9464228b7..78c8f369e 100644 --- a/src/sql/engine/expr/ob_expr_to_type.cpp +++ b/src/sql/engine/expr/ob_expr_to_type.cpp @@ -201,7 +201,8 @@ int ObExprToType::calc_result_type_for_column(ObExprResType &type, type.set_accuracy(ObAccuracy::MAX_ACCURACY2[get_compatibility_mode()][expect_type_]); if (ob_is_enumset_tc(type1.get_type())) { - ObObjType calc_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[expect_type_]]; + // There is no need to check whether it is enumset with subschema + ObObjType calc_type = get_enumset_calc_type(expect_type_, OB_INVALID_INDEX); if (OB_UNLIKELY(ObMaxType == calc_type)) { ret = OB_ERR_UNEXPECTED; SQL_ENG_LOG(WARN, "invalid type of parameter ", K(expect_type_), K(ret)); diff --git a/src/sql/engine/expr/ob_expr_type_to_str.cpp b/src/sql/engine/expr/ob_expr_type_to_str.cpp index 2c7b884d0..38905b8e9 100644 --- a/src/sql/engine/expr/ob_expr_type_to_str.cpp +++ b/src/sql/engine/expr/ob_expr_type_to_str.cpp @@ -62,7 +62,7 @@ int ObExprTypeToStr::calc_result_type2(ObExprResType &type, type.set_type(ObVarcharType); } else { ObObjType dst_type = static_cast(get_raw_expr()->get_extra()); - if (!ob_is_large_text(dst_type)) { + if (!ob_is_large_text(dst_type) && dst_type != ObCharType) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid dst type", K(ret), K(dst_type)); } else { @@ -255,7 +255,6 @@ int ObExprSetToStr::calc_to_str_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum { int ret = OB_SUCCESS; ObDatum *set_datum = NULL; - const ObString &sep = ObCharsetUtils::get_const_str(expr.datum_meta_.cs_type_, ','); if (OB_UNLIKELY(expr.arg_cnt_ != 2) || OB_ISNULL(expr.args_) || OB_ISNULL(expr.args_[1]) @@ -269,55 +268,66 @@ int ObExprSetToStr::calc_to_str_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum } else { ObIArray &str_values = static_cast(expr.extra_info_)->str_values_; uint64_t set_val = set_datum->get_set(); - - //在value存在重复的情况时,element_num会大于64,忽略64以后的值 - int64_t element_num = str_values.count(); - if (OB_UNLIKELY(element_num < 1)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid element num", K(element_num), K(ret)); - } else if (OB_UNLIKELY(element_num < EFFECTIVE_COUNT && set_val >= (1ULL << element_num))) { - ret = OB_ERR_DATA_TRUNCATED; - LOG_WARN("set value out of range", K(set_val), K(element_num)); + ObTextStringDatumResult text_result(expr.datum_meta_.type_, &expr, &ctx, &res_datum); + if (OB_FAIL(ObExprSetToStr::inner_to_str(expr.datum_meta_.cs_type_, set_val, str_values, + text_result))) { + LOG_WARN("enum to str failed", K(ret), K(set_val)); + } else { + text_result.set_result(); } + } + return ret; +} - int64_t need_size = 0; - uint64_t index = 1ULL; - for (int64_t i = 0; - OB_SUCC(ret) && i < element_num && i < EFFECTIVE_COUNT && set_val >= index; - ++i, index = index << 1) { - if (set_val & (index)) { - need_size += str_values.at(i).length(); - need_size += ((set_val >= (index << 1)) ? sep.length() : 0); - } +int ObExprSetToStr::inner_to_str(const ObCollationType cs_type, + const uint64_t set_val, + const ObIArray &str_values, + common::ObTextStringResult &text_result) +{ + int ret = OB_SUCCESS; + const ObString &sep = ObCharsetUtils::get_const_str(cs_type, ','); + // When there are duplicate values, element_num will be greater than 64, + // and values after 64 will be ignored. + int64_t element_num = str_values.count(); + if (OB_UNLIKELY(element_num < 1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid element num", K(element_num), K(ret)); + } else if (OB_UNLIKELY(element_num < EFFECTIVE_COUNT && set_val >= (1ULL << element_num))) { + ret = OB_ERR_DATA_TRUNCATED; + LOG_WARN("set value out of range", K(set_val), K(element_num)); + } + + int64_t need_size = 0; + uint64_t index = 1ULL; + for (int64_t i = 0; + OB_SUCC(ret) && i < element_num && i < EFFECTIVE_COUNT && set_val >= index; + ++i, index = index << 1) { + if (set_val & (index)) { + need_size += str_values.at(i).length(); + need_size += ((set_val >= (index << 1)) ? sep.length() : 0); } + } - if (OB_SUCC(ret)) { - int64_t pos = 0; - char *buf = NULL; - ObTextStringDatumResult text_result(expr.datum_meta_.type_, &expr, &ctx, &res_datum); - if (OB_FAIL(text_result.init(need_size))) { - LOG_WARN("init lob result failed", K(ret), K(need_size)); - } else { - uint64_t index = 1ULL; - for (int64_t i = 0; - OB_SUCC(ret) && i < element_num && i < EFFECTIVE_COUNT && set_val >= index; - ++i, index = index << 1) { - if (set_val & (index)) { - const ObString &element_val = str_values.at(i); - if (OB_FAIL(text_result.append(element_val))) { - LOG_WARN("fail to append str to lob result", K(ret), K(element_val)); - } else if ((i + 1) < element_num && (i + 1) < EFFECTIVE_COUNT && - ((index << 1) <= set_val)) { - // skip setting last seperator - if (OB_FAIL(text_result.append(sep))) { - LOG_WARN("fail to append str to lob result", K(ret), K(sep)); - } + if (OB_SUCC(ret)) { + if (OB_FAIL(text_result.init(need_size))) { + LOG_WARN("init lob result failed", K(ret), K(need_size)); + } else { + uint64_t index = 1ULL; + for (int64_t i = 0; + OB_SUCC(ret) && i < element_num && i < EFFECTIVE_COUNT && set_val >= index; + ++i, index = index << 1) { + if (set_val & (index)) { + const ObString &element_val = str_values.at(i); + if (OB_FAIL(text_result.append(element_val))) { + LOG_WARN("fail to append str to lob result", K(ret), K(element_val)); + } else if ((i + 1) < element_num && (i + 1) < EFFECTIVE_COUNT && + ((index << 1) <= set_val)) { + // skip setting last seperator + if (OB_FAIL(text_result.append(sep))) { + LOG_WARN("fail to append str to lob result", K(ret), K(sep)); } } } - if (OB_SUCC(ret)) { - text_result.set_result(); - } } } } @@ -365,32 +375,41 @@ int ObExprEnumToStr::calc_to_str_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatu res_datum.set_null(); } else { ObIArray &str_values = static_cast(expr.extra_info_)->str_values_; - char *buf = NULL; uint64_t enum_val = enum_datum->get_enum(); - int64_t element_num = str_values.count(); - uint64_t element_idx = enum_val - 1; - ObString element_str; - if (OB_UNLIKELY(element_num < 1)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid element num", K(element_num), K(element_num)); - } else if (0 == enum_val) { - // ObString empty_string; - // res_datum.set_enumset_inner(empty_string.make_empty_string()); - } else if (OB_UNLIKELY(element_idx > element_num - 1)) { - ret = OB_ERR_DATA_TRUNCATED; - LOG_WARN("enum value out of range", K(element_idx), K(element_num), K(ret)); + ObTextStringDatumResult text_result(expr.datum_meta_.type_, &expr, &ctx, &res_datum); + if (OB_FAIL(ObExprEnumToStr::inner_to_str(enum_val, str_values, text_result))) { + LOG_WARN("enum to str failed", K(ret), K(enum_val)); } else { - element_str = str_values.at(element_idx); + text_result.set_result(); } - if (OB_SUCC(ret)) { - ObTextStringDatumResult text_result(expr.datum_meta_.type_, &expr, &ctx, &res_datum); - if (OB_FAIL(text_result.init(element_str.length()))) { - LOG_WARN("init lob result failed"); - } else if (OB_FAIL(text_result.append(element_str.ptr(), element_str.length()))) { - LOG_WARN("failed to append realdata", K(ret), K(text_result)); - } else { - text_result.set_result(); - } + } + return ret; +} + +int ObExprEnumToStr::inner_to_str(const uint64_t enum_val, + const ObIArray &str_values, + common::ObTextStringResult &text_result) +{ + int ret = OB_SUCCESS; + const int64_t element_num = str_values.count(); + const uint64_t element_idx = enum_val - 1; + ObString element_str; + if (OB_UNLIKELY(element_num < 1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid element num", K(element_num), K(element_num)); + } else if (0 == enum_val) { + // ObString empty_string; + } else if (OB_UNLIKELY(element_idx > element_num - 1)) { + ret = OB_ERR_DATA_TRUNCATED; + LOG_WARN("enum value out of range", K(element_idx), K(element_num), K(ret)); + } else { + element_str = str_values.at(element_idx); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(text_result.init(element_str.length()))) { + LOG_WARN("init lob result failed"); + } else if (OB_FAIL(text_result.append(element_str.ptr(), element_str.length()))) { + LOG_WARN("failed to append real data", K(ret), K(text_result)); } } return ret; diff --git a/src/sql/engine/expr/ob_expr_type_to_str.h b/src/sql/engine/expr/ob_expr_type_to_str.h index 5c8ecaf6f..67e0bf333 100644 --- a/src/sql/engine/expr/ob_expr_type_to_str.h +++ b/src/sql/engine/expr/ob_expr_type_to_str.h @@ -15,6 +15,7 @@ #include "sql/engine/expr/ob_expr_operator.h" #include "sql/engine/expr/ob_i_expr_extra_info.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" namespace oceanbase { @@ -110,7 +111,10 @@ public: const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; static int calc_to_str_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res_datum); - + static int inner_to_str(const ObCollationType cs_type, + const uint64_t enum_val, + const ObIArray &str_values, + common::ObTextStringResult &text_result); private: // disallow copy DISALLOW_COPY_AND_ASSIGN(ObExprSetToStr) const; @@ -125,6 +129,9 @@ public: const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; static int calc_to_str_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res_datum); + static int inner_to_str(const uint64_t enum_val, + const ObIArray &str_values, + common::ObTextStringResult &text_result); private: // disallow copy DISALLOW_COPY_AND_ASSIGN(ObExprEnumToStr) const; diff --git a/src/sql/engine/ob_exec_context.cpp b/src/sql/engine/ob_exec_context.cpp index a3dfd12e3..0f062880c 100644 --- a/src/sql/engine/ob_exec_context.cpp +++ b/src/sql/engine/ob_exec_context.cpp @@ -26,6 +26,7 @@ #include "ob_operator.h" #include "observer/ob_server.h" #include "storage/lob/ob_lob_persistent_reader.h" +#include "sql/executor/ob_memory_tracker.h" #ifdef OB_BUILD_SPM #include "sql/spm/ob_spm_controller.h" #endif @@ -509,6 +510,8 @@ int ObExecContext::check_status() LOG_WARN("px execution was interrupted", K(ic), K(ret)); } else if (lib::Worker::WS_OUT_OF_THROTTLE == THIS_WORKER.check_wait()) { ret = OB_KILLED_BY_THROTTLING; + } else if (OB_UNLIKELY((OB_SUCCESS != (ret = CHECK_MEM_STATUS())))) { + LOG_WARN("Exceeded memory usage limit", K(ret)); } int tmp_ret = OB_SUCCESS; if (OB_SUCCESS != (tmp_ret = check_extra_status())) { @@ -1211,6 +1214,22 @@ int ObExecContext::get_sqludt_meta_by_subschema_id(uint16_t subschema_id, ObSubS return ret; } +int ObExecContext::get_enumset_meta_by_subschema_id(uint16_t subschema_id, + const ObEnumSetMeta *&meta) const +{ + int ret = OB_SUCCESS; + if (ob_is_reserved_subschema_id(subschema_id)) { + ret = OB_ERR_UNEXPECTED; + SQL_ENG_LOG(WARN, "reserved subschema id not used in enumset meta", K(ret), K(lbt())); + } else if (OB_ISNULL(phy_plan_ctx_)) { + ret = OB_NOT_INIT; + SQL_ENG_LOG(WARN, "not phyical plan ctx for subschema mapping", K(ret), K(lbt())); + } else { + ret = phy_plan_ctx_->get_enumset_meta_by_subschema_id(subschema_id, meta); + } + return ret; +} + int ObExecContext::get_subschema_id_by_udt_id(uint64_t udt_type_id, uint16_t &subschema_id, share::schema::ObSchemaGetterGuard *schema_guard) @@ -1242,6 +1261,44 @@ int ObExecContext::get_subschema_id_by_collection_elem_type(ObNestedType coll_ty return ret; } +bool ObExecContext::support_enum_set_type_subschema(ObSQLSessionInfo &session) +{ + // Considering compatibility, enumset subschema is only supported in versions [4_2_5, 4_3_0) and + // versions 4_3_5 at least. + bool bret = true; + const uint64_t min_cluster_version = GET_MIN_CLUSTER_VERSION(); + if ((min_cluster_version < MOCK_CLUSTER_VERSION_4_2_5_0) || + (min_cluster_version >= CLUSTER_VERSION_4_3_0_0 + && min_cluster_version < CLUSTER_VERSION_4_3_5_0)) { + bret = false; + } else { + // tenant configuration Control + if (!session.is_enable_enum_set_with_subschema()) { + bret = false; + } + // hint control + if (OB_NOT_NULL(stmt_factory_) && OB_NOT_NULL(stmt_factory_->get_query_ctx())) { + stmt_factory_->get_query_ctx()->get_global_hint().opt_params_.get_bool_opt_param( + ObOptParamHint::ENABLE_ENUM_SET_SUBSCHEMA, bret); + } + } + return bret; +} + +int ObExecContext::get_subschema_id_by_type_info(const ObObjMeta &obj_meta, + const ObIArray &type_info, + uint16_t &subschema_id) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(phy_plan_ctx_)) { + ret = OB_NOT_INIT; + SQL_ENG_LOG(WARN, "not phyical plan ctx for reverse mapping", K(ret), K(lbt())); + } else { + ret = phy_plan_ctx_->get_subschema_id_by_type_info(obj_meta, type_info, subschema_id); + } + return ret; +} + int ObExecContext::get_subschema_id_by_type_string(const ObString &type_string, uint16_t &subschema_id) { int ret = OB_SUCCESS; diff --git a/src/sql/engine/ob_exec_context.h b/src/sql/engine/ob_exec_context.h index 934aad205..af545d0bf 100644 --- a/src/sql/engine/ob_exec_context.h +++ b/src/sql/engine/ob_exec_context.h @@ -514,6 +514,11 @@ public: const ObDataType &elem_type, uint16_t &subschema_id); int get_subschema_id_by_type_string(const ObString &type_string, uint16_t &subschema_id); + int get_enumset_meta_by_subschema_id(uint16_t subschema_id, const ObEnumSetMeta *&meta) const; + bool support_enum_set_type_subschema(ObSQLSessionInfo &session); + int get_subschema_id_by_type_info(const ObObjMeta &obj_meta, + const ObIArray &type_info, + uint16_t &subschema_id); ObExecFeedbackInfo &get_feedback_info() { return fb_info_; }; inline void set_cur_rownum(int64_t cur_rownum) { user_logging_ctx_.row_num_ = cur_rownum; } inline int64_t get_cur_rownum() const { return user_logging_ctx_.row_num_; } diff --git a/src/sql/engine/ob_operator_reg.h b/src/sql/engine/ob_operator_reg.h index e22ca7582..d95632e7d 100644 --- a/src/sql/engine/ob_operator_reg.h +++ b/src/sql/engine/ob_operator_reg.h @@ -438,7 +438,7 @@ REGISTER_OPERATOR(ObLogJoin, PHY_NESTED_LOOP_CONNECT_BY_WITH_INDEX, class ObLogJoin; class ObNLConnectBySpec; class ObNLConnectByOp; -REGISTER_OPERATOR(ObLogJoin, PHY_NESTED_LOOP_CONNECT_BY, ObNLConnectBySpec, +REGISTER_OPERATOR(ObLogJoin, PHY_CONNECT_BY, ObNLConnectBySpec, ObNLConnectByOp, NOINPUT); class ObLogJoin; diff --git a/src/sql/engine/ob_phy_operator_type.h b/src/sql/engine/ob_phy_operator_type.h index 02a1c0ad5..43f469274 100644 --- a/src/sql/engine/ob_phy_operator_type.h +++ b/src/sql/engine/ob_phy_operator_type.h @@ -102,7 +102,7 @@ PHY_OP_DEF(PHY_PX_MULTI_PART_DELETE) PHY_OP_DEF(PHY_PX_MULTI_PART_UPDATE) PHY_OP_DEF(PHY_PX_MULTI_PART_INSERT) PHY_OP_DEF(PHY_UNPIVOT) -PHY_OP_DEF(PHY_NESTED_LOOP_CONNECT_BY) /*90*/ +PHY_OP_DEF(PHY_CONNECT_BY) /*90*/ PHY_OP_DEF(PHY_LINK_SCAN) PHY_OP_DEF(PHY_LOCK) PHY_OP_DEF(PHY_MULTI_LOCK) diff --git a/src/sql/engine/ob_physical_plan_ctx.cpp b/src/sql/engine/ob_physical_plan_ctx.cpp index 931396bd3..f262a14e9 100644 --- a/src/sql/engine/ob_physical_plan_ctx.cpp +++ b/src/sql/engine/ob_physical_plan_ctx.cpp @@ -1115,6 +1115,44 @@ int ObPhysicalPlanCtx::get_sqludt_meta_by_subschema_id(uint16_t subschema_id, Ob return ret; } +int ObPhysicalPlanCtx::get_enumset_meta_by_subschema_id(uint16_t subschema_id, + const ObEnumSetMeta *&meta) const +{ + int ret = OB_SUCCESS; + ObSubSchemaValue value; + if (subschema_id == ObMaxSystemUDTSqlType || subschema_id >= UINT_MAX16) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema id", K(ret), K(subschema_id)); + } else if (OB_NOT_NULL(phy_plan_)) { // physical plan exist, use subschema ctx on phy plan + if (!phy_plan_->get_subschema_ctx().is_inited()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("plan with empty subschema mapping", K(ret), K(phy_plan_->get_subschema_ctx())); + } else if (OB_FAIL(phy_plan_->get_subschema_ctx().get_subschema(subschema_id, value))) { + if (OB_HASH_NOT_EXIST != ret) { + LOG_WARN("failed to get subschema by subschema id", K(ret), K(subschema_id)); + } else { + LOG_WARN("subschema not exist in subschema mapping", K(ret), K(subschema_id)); + } + } else { + meta = reinterpret_cast(value.value_); + } + } else if (!subschema_ctx_.is_inited()) { // no phy plan + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema id", K(ret), K(subschema_id), K(lbt())); + } else { + if (OB_FAIL(subschema_ctx_.get_subschema(subschema_id, value))) { + LOG_WARN("failed to get subschema", K(ret), K(subschema_id)); + } else if (value.type_ >= OB_SUBSCHEMA_MAX_TYPE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema type", K(ret), K(value)); + } else { // Notice: shallow copy + meta = reinterpret_cast(value.value_); + } + } + LOG_TRACE("ENUMSET: search subschema", K(ret), KP(this), K(subschema_id)); + return ret; +} + int ObPhysicalPlanCtx::get_subschema_id_by_udt_id(uint64_t udt_type_id, uint16_t &subschema_id, share::schema::ObSchemaGetterGuard *schema_guard) @@ -1237,6 +1275,51 @@ int ObPhysicalPlanCtx::get_subschema_id_by_type_string(const ObString &type_stri return ret; } +int ObPhysicalPlanCtx::get_subschema_id_by_type_info(const ObObjMeta &obj_meta, + const ObIArray &type_info, + uint16_t &subschema_id) +{ + int ret = OB_SUCCESS; + uint16_t temp_subschema_id = ObMaxSystemUDTSqlType; + bool found = false; + ObEnumSetMeta src_meta(obj_meta, &type_info); + if (OB_NOT_NULL(phy_plan_)) { // physical plan exist, use subschema ctx on phy plan + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get type info when physical plan exist is not unexpected", K(ret), K(type_info)); + } else if (!subschema_ctx_.is_inited() && OB_FAIL(subschema_ctx_.init())) { + LOG_WARN("subschema ctx init failed", K(ret)); + } else if (OB_FAIL(subschema_ctx_.get_subschema_id(OB_SUBSCHEMA_ENUM_SET_TYPE, + src_meta, + temp_subschema_id))) { + if (OB_HASH_NOT_EXIST != ret) { + LOG_WARN("failed to get subschema id by udt_id", K(ret), K(type_info)); + } else { // build new meta + ret = OB_SUCCESS; + uint16 new_subschema_id = ObMaxSystemUDTSqlType; + ObSubSchemaValue value; + ObEnumSetMeta *dst_meta = NULL; + if (OB_FAIL(src_meta.deep_copy(allocator_, dst_meta))) { + LOG_WARN("fail to deep copy enumset meta", K(ret)); + } else if (OB_FAIL(subschema_ctx_.get_new_subschema_id(new_subschema_id))) { + LOG_WARN("failed to get new subschema id", K(ret), K(get_tenant_id())); + } else { + value.type_ = OB_SUBSCHEMA_ENUM_SET_TYPE; + value.signature_ = dst_meta->get_signature(); + value.value_ = static_cast(dst_meta); + if (OB_FAIL(subschema_ctx_.set_subschema(new_subschema_id, value))) { + LOG_WARN("failed to set new subschema", K(ret), K(new_subschema_id), K(value)); + } else { + subschema_id = new_subschema_id; + } + } + LOG_TRACE("ENUMSET: build subschema", K(ret), KP(this), K(subschema_id)); + } + } else { // success + subschema_id = temp_subschema_id; + } + return ret; +} + int ObPhysicalPlanCtx::set_all_local_session_vars(ObIArray &all_local_session_vars) { int ret = OB_SUCCESS; diff --git a/src/sql/engine/ob_physical_plan_ctx.h b/src/sql/engine/ob_physical_plan_ctx.h index cf9898ac0..4c711b974 100644 --- a/src/sql/engine/ob_physical_plan_ctx.h +++ b/src/sql/engine/ob_physical_plan_ctx.h @@ -24,6 +24,7 @@ #include "sql/engine/user_defined_function/ob_udf_ctx_mgr.h" #include "sql/engine/expr/ob_expr.h" #include "lib/udt/ob_udt_type.h" +#include "lib/enumset/ob_enum_set_meta.h" #include "sql/engine/ob_subschema_ctx.h" #include "sql/engine/expr/ob_expr_util.h" @@ -508,6 +509,7 @@ public: int get_sqludt_meta_by_subschema_id(uint16_t subschema_id, ObSqlUDTMeta &udt_meta); int get_sqludt_meta_by_subschema_id(uint16_t subschema_id, ObSubSchemaValue &sub_meta); bool is_subschema_ctx_inited(); + int get_enumset_meta_by_subschema_id(uint16_t subschema_id, const ObEnumSetMeta *&meta) const; int get_subschema_id_by_udt_id(uint64_t udt_type_id, uint16_t &subschema_id, share::schema::ObSchemaGetterGuard *schema_guard = NULL); @@ -515,6 +517,9 @@ public: const ObDataType &elem_type, uint16_t &subschema_id); int get_subschema_id_by_type_string(const ObString &type_string, uint16_t &subschema_id); + int get_subschema_id_by_type_info(const ObObjMeta &obj_meta, + const ObIArray &type_info, + uint16_t &subschema_id); int build_subschema_by_fields(const ColumnsFieldIArray *fields, share::schema::ObSchemaGetterGuard *schema_guard); int build_subschema_ctx_by_param_store(share::schema::ObSchemaGetterGuard *schema_guard); diff --git a/src/sql/engine/ob_subschema_ctx.cpp b/src/sql/engine/ob_subschema_ctx.cpp index a5fdd96d2..dbcd5d223 100644 --- a/src/sql/engine/ob_subschema_ctx.cpp +++ b/src/sql/engine/ob_subschema_ctx.cpp @@ -14,6 +14,7 @@ #include "sql/engine/ob_subschema_ctx.h" #include "deps/oblib/src/lib/udt/ob_udt_type.h" #include "deps/oblib/src/lib/udt/ob_array_type.h" +#include "lib/enumset/ob_enum_set_meta.h" #include "src/share/rc/ob_tenant_base.h" namespace oceanbase @@ -28,192 +29,130 @@ namespace sql // Add New de/serialize functions for schema value when new subschema types are added. // Signature is identify of subschema value, using for reverse search of subschema id // for sql udt, signature is original udt id -#define DEF_SUBSCHEMA_ENTRY(SUBSCHEMATYPE) \ - { \ - subschema_value_serialize, \ - subschema_value_deserialize, \ - subschema_value_serialize_size, \ - subschema_value_get_signature, \ - subschema_value_deep_copy, \ +#define DEF_SUBSCHEMA_ENTRY(SUBSCHEMATYPE, CLZ) \ + { \ + subschema_value_serialize, \ + subschema_value_deserialize, \ + subschema_value_serialize_size, \ + subschema_value_get_signature, \ + subschema_value_deep_copy, \ + subschema_value_init, \ } -template<> -int subschema_value_serialize(void *value, char* buf, const int64_t buf_len, int64_t& pos) +template +int subschema_value_serialize(void *value, char* buf, const int64_t buf_len, int64_t& pos) { int ret = OB_SUCCESS; if (OB_ISNULL(value)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("null sql udt value for seriazlie", K(ret), K(OB_SUBSCHEMA_UDT_TYPE)); + LOG_WARN("null sql subschema value for serialize", K(ret), K(TYPE)); } else { - const ObSqlUDTMeta* udt_meta = reinterpret_cast(value); - if (OB_FAIL(udt_meta->serialize(buf, buf_len, pos))) { - LOG_WARN("failed to do sql udt meta seriazlie", K(ret), K(*udt_meta)); + const CLZ *subschema_value = reinterpret_cast(value); + if (OB_FAIL(subschema_value->serialize(buf, buf_len, pos))) { + LOG_WARN("failed to do sql subschema value serialize", K(ret), K(*subschema_value)); } } return ret; } -template <> -int subschema_value_deserialize(void *value, const char* buf, const int64_t data_len, int64_t& pos) +template +int subschema_value_deserialize(void *value, const char* buf, const int64_t data_len, int64_t& pos) { int ret = OB_SUCCESS; if (OB_ISNULL(value)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("null sql udt value for deseriazlie", K(ret), K(OB_SUBSCHEMA_UDT_TYPE)); + LOG_WARN("null sql subschema value for deserialize", K(ret), K(TYPE)); } else { - ObSqlUDTMeta* udt_meta = reinterpret_cast(value); - if (OB_FAIL(udt_meta->deserialize(buf, data_len, pos))) { - LOG_WARN("failed to do sql udt meta deseriazlie", K(ret), KP(buf), K(data_len)); + CLZ *subschema_value = reinterpret_cast(value); + if (OB_FAIL(subschema_value->deserialize(buf, data_len, pos))) { + LOG_WARN("failed to do sql subschema value deserialize", K(ret), KP(buf), K(data_len)); } } return ret; } -template <> -int64_t subschema_value_serialize_size(void *value) +template +int64_t subschema_value_serialize_size(void *value) { int ret = OB_SUCCESS; int64_t len = 0; if (OB_ISNULL(value)) { } else { - ObSqlUDTMeta* udt_meta = reinterpret_cast(value); - len += udt_meta->get_serialize_size(); + const CLZ *subschema_value = reinterpret_cast(value); + len += subschema_value->get_serialize_size(); } return len; } -template <> -int subschema_value_get_signature(void *value, uint64_t &signature) +template +int subschema_value_get_signature(void *value, uint64_t &signature) { int ret = OB_SUCCESS; signature = 0; if (OB_ISNULL(value)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("null subschema value", K(ret), K(OB_SUBSCHEMA_UDT_TYPE)); + LOG_WARN("null subschema value", K(ret), K(TYPE)); } else { - const ObSqlUDTMeta* udt_meta = reinterpret_cast(value); - signature = udt_meta->udt_id_; + const CLZ *subschema_value = reinterpret_cast(value); + signature = subschema_value->get_signature(); } return ret; } -template <> -int subschema_value_deep_copy(const void *src_value, void *&dst_value, ObIAllocator &allocator) +template +int subschema_value_deep_copy(const void *src_value, void *&dst_value, ObIAllocator &allocator) { int ret = OB_SUCCESS; if (OB_ISNULL(src_value)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("null subschema value for deep copy", K(ret), K(OB_SUBSCHEMA_UDT_TYPE)); + LOG_WARN("null subschema value for deep copy", K(ret), K(TYPE)); } else { - const ObSqlUDTMeta* udt_meta = reinterpret_cast(src_value); - ObSqlUDTMeta* copy_meta = NULL; - if (OB_FAIL(udt_meta->deep_copy(allocator, copy_meta))) { - LOG_WARN("failed to deep copy udt meta", K(ret), K(OB_SUBSCHEMA_UDT_TYPE)); - } else if (OB_ISNULL(copy_meta)) { + const CLZ *src_subschema_value = reinterpret_cast(src_value); + CLZ* copy_value = NULL; + if (OB_FAIL(src_subschema_value->deep_copy(allocator, copy_value))) { + LOG_WARN("failed to deep copy subschema value", K(ret), K(TYPE)); + } else if (OB_ISNULL(copy_value)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("deep copy udt meta result is null", K(ret), K(OB_SUBSCHEMA_UDT_TYPE)); + LOG_WARN("deep copy subschema value result is null", K(ret), K(TYPE)); } else { - dst_value = static_cast(copy_meta); + dst_value = static_cast(copy_value); } } return ret; } -template<> -int subschema_value_serialize(void *value, char* buf, const int64_t buf_len, int64_t& pos) +template +int subschema_value_init(void *&value, ObIAllocator &allocator) { int ret = OB_SUCCESS; - if (OB_ISNULL(value)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("null sql udt value for seriazlie", K(ret), K(OB_SUBSCHEMA_COLLECTION_TYPE)); + void *mem = value; + if (OB_NOT_NULL(mem)) { + ret = OB_INIT_TWICE; + LOG_WARN("value is not null", K(ret), KP(value)); + } else if (OB_ISNULL(mem = allocator.alloc(sizeof(CLZ)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc value", K(ret), K(TYPE)); } else { - const ObSqlCollectionInfo* coll_meta = reinterpret_cast(value); - if (OB_FAIL(coll_meta->serialize(buf, buf_len, pos))) { - LOG_WARN("failed to do sql udt meta seriazlie", K(ret), K(*coll_meta)); - } - } - - return ret; -} - -template <> -int subschema_value_deserialize(void *value, const char* buf, const int64_t data_len, int64_t& pos) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(value)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("null sql udt value for deseriazlie", K(ret), K(OB_SUBSCHEMA_COLLECTION_TYPE)); - } else { - ObSqlCollectionInfo* coll_meta = reinterpret_cast(value); - if (OB_FAIL(coll_meta->deserialize(buf, data_len, pos))) { - LOG_WARN("failed to do sql udt meta deseriazlie", K(ret), KP(buf), K(data_len)); - } - } - return ret; -} - -template <> -int64_t subschema_value_serialize_size(void *value) -{ - int ret = OB_SUCCESS; - int64_t len = 0; - if (OB_ISNULL(value)) { - } else { - ObSqlCollectionInfo* coll_meta = reinterpret_cast(value); - len += coll_meta->get_serialize_size(); - } - return len; -} - -template <> -int subschema_value_get_signature(void *value, uint64_t &signature) -{ - int ret = OB_SUCCESS; - signature = 0; - if (OB_ISNULL(value)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("null subschema value", K(ret), K(OB_SUBSCHEMA_COLLECTION_TYPE)); - } else { - const ObSqlCollectionInfo* coll_meta = reinterpret_cast(value); - signature = coll_meta->get_def_string().hash(); - } - return ret; -} - -template <> -int subschema_value_deep_copy(const void *src_value, void *&dst_value, ObIAllocator &allocator) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(src_value)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("null subschema value for deep copy", K(ret), K(OB_SUBSCHEMA_COLLECTION_TYPE)); - } else { - const ObSqlCollectionInfo* coll_meta = reinterpret_cast(src_value); - ObSqlCollectionInfo* copy_meta = NULL; - if (OB_FAIL(coll_meta->deep_copy(allocator, copy_meta))) { - LOG_WARN("failed to deep copy udt meta", K(ret), K(OB_SUBSCHEMA_COLLECTION_TYPE)); - } else if (OB_ISNULL(copy_meta)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("deep copy udt meta result is null", K(ret), K(OB_SUBSCHEMA_COLLECTION_TYPE)); - } else { - dst_value = static_cast(copy_meta); - } + CLZ *meta = new(mem)CLZ(&allocator); + value = meta; } return ret; } ObSubSchemaFuncs SUBSCHEMA_FUNCS[OB_SUBSCHEMA_MAX_TYPE] = { - DEF_SUBSCHEMA_ENTRY(OB_SUBSCHEMA_UDT_TYPE), - DEF_SUBSCHEMA_ENTRY(OB_SUBSCHEMA_ENUM_SET_TYPE), - DEF_SUBSCHEMA_ENTRY(OB_SUBSCHEMA_COLLECTION_TYPE), + DEF_SUBSCHEMA_ENTRY(OB_SUBSCHEMA_UDT_TYPE, ObSqlUDTMeta), + DEF_SUBSCHEMA_ENTRY(OB_SUBSCHEMA_ENUM_SET_TYPE, ObEnumSetMeta), + DEF_SUBSCHEMA_ENTRY(OB_SUBSCHEMA_COLLECTION_TYPE, ObSqlCollectionInfo), }; int ObSubSchemaValue::deep_copy_value(const void *src_value, ObIAllocator &allocator) { int ret = OB_SUCCESS; - if (OB_ISNULL(src_value)) { + if (!is_valid_type(type_)) { + // do nothing + } else if (OB_ISNULL(src_value)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null value for deep copy subschema value", K(ret)); } else if (OB_FAIL(SUBSCHEMA_FUNCS[type_].deep_copy(src_value, value_, allocator))) { @@ -231,7 +170,8 @@ OB_DEF_SERIALIZE(ObSubSchemaValue) signature_); if (OB_FAIL(ret)) { LOG_WARN("fail to serialize subschema type info", K(ret), K(type_), K(signature_)); - } else if (OB_FAIL(SUBSCHEMA_FUNCS[type_].value_serialize(value_, buf, buf_len, pos))) { + } else if (is_valid_type(type_) && + OB_FAIL(SUBSCHEMA_FUNCS[type_].value_serialize(value_, buf, buf_len, pos))) { LOG_WARN("fail to serialize subschema data", K(ret), K(type_), K(signature_)); } return ret; @@ -248,26 +188,16 @@ OB_DEF_DESERIALIZE(ObSubSchemaValue) } else if (OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("allocator is null", K(ret), K(type_), K(signature_)); - } else if (type_ == ObSubSchemaType::OB_SUBSCHEMA_UDT_TYPE) { - ObSqlUDTMeta *udt_meta = OB_NEWx(ObSqlUDTMeta, allocator_); - if (OB_ISNULL(udt_meta)) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("alloc udt meta memory failed", K(ret)); + } else if (is_valid_type(type_)) { + ObIAllocator *alloc = allocator_; + void *value_meta = NULL; + if (OB_FAIL(SUBSCHEMA_FUNCS[type_].init(value_meta, *alloc))) { + LOG_WARN("fail to init value", K(ret)); + } else if (OB_FAIL(SUBSCHEMA_FUNCS[type_].value_deserialize(value_meta, buf, data_len, pos))) { + LOG_WARN("fail to deserialize subschema data", K(ret), K(type_), K(signature_)); } else { - value_ = udt_meta; + value_ = value_meta; } - } else if (type_ == ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { - ObSqlCollectionInfo *coll_meta = OB_NEWx(ObSqlCollectionInfo, allocator_, *allocator_); - if (OB_ISNULL(coll_meta)) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("alloc collection info memory failed", K(ret)); - } else { - value_ = coll_meta; - } - } - if (OB_FAIL(ret)) { - } else if (OB_FAIL(SUBSCHEMA_FUNCS[type_].value_deserialize(value_, buf, data_len, pos))) { - LOG_WARN("fail to deserialize subschema data", K(ret), K(type_), K(signature_)); } return ret; } @@ -279,7 +209,9 @@ OB_DEF_SERIALIZE_SIZE(ObSubSchemaValue) LST_DO_CODE(OB_UNIS_ADD_LEN, type_, signature_); - len += SUBSCHEMA_FUNCS[type_].get_value_serialize_size(value_); + if (is_valid_type(type_)) { + len += SUBSCHEMA_FUNCS[type_].get_value_serialize_size(value_); + } return len; } @@ -287,19 +219,19 @@ OB_DEF_SERIALIZE_SIZE(ObSubSchemaValue) OB_DEF_SERIALIZE(ObSubSchemaCtx) { int ret = OB_SUCCESS; - if (!is_inited_ || subschema_map_.empty()) { // do nothing + if (!is_inited_ || subschema_array_.empty()) { // do nothing } else { // subschema count more then zero - uint32_t subschema_count = subschema_map_.size(); + const uint32_t subschema_count = subschema_array_.count(); OB_UNIS_ENCODE(subschema_count); OB_UNIS_ENCODE(used_subschema_id_); if (OB_FAIL(ret)) { LOG_WARN("fail to serialize subschema ctx", K(ret)); } else { - ObSubSchemaMap::const_iterator iter = subschema_map_.begin(); - while (OB_SUCC(ret) && iter != subschema_map_.end()) { - OB_UNIS_ENCODE(iter->first); - OB_UNIS_ENCODE(iter->second); - iter++; + for (int64_t i = 0; OB_SUCC(ret) && i < subschema_array_.count(); ++i) { + if (OB_LIKELY(subschema_array_.at(i).is_valid())) { + OB_UNIS_ENCODE(i); + OB_UNIS_ENCODE(subschema_array_.at(i)); + } } } } @@ -326,9 +258,9 @@ OB_DEF_DESERIALIZE(ObSubSchemaCtx) value.allocator_ = &allocator_; OB_UNIS_DECODE(subschema_id); OB_UNIS_DECODE(value); - if (OB_FAIL(ret)) { + if (OB_FAIL(ret)) { // copy value from buffer to local memory } else if (OB_FAIL(set_subschema(subschema_id, value))) { - LOG_WARN("fail to set subschema", K(ret), K(subschema_id), K(value)); + LOG_WARN("fail to set subschema", K(ret), K(subschema_id), K(value)); } } } @@ -341,16 +273,16 @@ OB_DEF_DESERIALIZE(ObSubSchemaCtx) OB_DEF_SERIALIZE_SIZE(ObSubSchemaCtx) { int64_t len = 0; - if (!is_inited_ || subschema_map_.empty()) { // do nothing + if (!is_inited_ || subschema_array_.empty()) { // do nothing } else { // subschema count more then zero - uint32_t subschema_count = subschema_map_.size(); + uint32_t subschema_count = subschema_array_.count(); OB_UNIS_ADD_LEN(subschema_count); OB_UNIS_ADD_LEN(used_subschema_id_); - ObSubSchemaMap::const_iterator iter = subschema_map_.begin(); - while (iter != subschema_map_.end()) { - OB_UNIS_ADD_LEN(iter->first); - OB_UNIS_ADD_LEN(iter->second); - iter++; + for (int64_t i = 0; i < subschema_array_.count(); ++i) { + if (OB_LIKELY(subschema_array_.at(i).is_valid())) { + OB_UNIS_ADD_LEN(i); + OB_UNIS_ADD_LEN(subschema_array_.at(i)); + } } } return len; @@ -369,16 +301,15 @@ int ObSubSchemaCtx::assgin(const ObSubSchemaCtx &other) if (!is_inited() && OB_FAIL(init())) { LOG_WARN("fail to init subschema ctx", K(ret)); } else { - ObSubSchemaMap::const_iterator iter = other.get_subschema_map().begin(); - while (OB_SUCC(ret) && iter != other.get_subschema_map().end()) { - uint64_t subschema_id = iter->first; - ObSubSchemaValue value = iter->second; - if (OB_FAIL(value.deep_copy_value(iter->second.value_, allocator_))) { - LOG_WARN("deep copy value failed", K(ret), K(subschema_id), K(value)); - } else if (OB_FAIL(set_subschema(subschema_id, value))) { - LOG_WARN("fail to set subschema", K(ret), K(subschema_id), K(value)); + for (int64_t i = 0; OB_SUCC(ret) && i < other.get_subschema_array().count(); ++i) { + uint64_t subschema_id = i; + const ObSubSchemaValue src = other.get_subschema_array().at(subschema_id); + ObSubSchemaValue dst = src; + if (OB_FAIL(dst.deep_copy_value(src.value_, allocator_))) { + LOG_WARN("deep copy value failed", K(ret), K(i), K(dst)); + } else if (OB_FAIL(set_subschema(i, dst))) { + LOG_WARN("fail to set subschema", K(ret), K(i), K(dst)); } - iter++; } used_subschema_id_ = other.used_subschema_id_; } @@ -397,17 +328,17 @@ int ObSubSchemaCtx::init() if (tenant_id == OB_INVALID_TENANT_ID) { tenant_id = OB_SERVER_TENANT_ID; } - if (OB_FAIL(subschema_map_.create(SUBSCHEMA_BUCKET_NUM, - "SubSchemaHash", - "SubSchemaHash", - tenant_id))) { - LOG_WARN("fail to create subschema map", K(ret)); - } else if (OB_FAIL(subschema_reverse_map_.create(SUBSCHEMA_BUCKET_NUM, + if (OB_FAIL(subschema_reverse_map_.create(SUBSCHEMA_BUCKET_NUM, "SubSchemaRev", "SubSchemaRev", tenant_id))) { LOG_WARN("fail to create subschema map", K(ret)); + } else if (OB_FAIL(enum_set_meta_reverse_map_.create(SUBSCHEMA_BUCKET_NUM, + "SubSchemaRev", + "SubSchemaRev", + tenant_id))) { } else { + subschema_array_.set_attr(ObMemAttr(MTL_ID(), "SubSchemaHash")); is_inited_ = true; used_subschema_id_ = MAX_NON_RESERVED_SUBSCHEMA_ID; } @@ -418,8 +349,9 @@ int ObSubSchemaCtx::init() void ObSubSchemaCtx::reset() { // content in subschema value is alloc from plan object allocator? need a new allocator? if (is_inited_) { - subschema_map_.destroy(); + subschema_array_.destroy(); subschema_reverse_map_.destroy(); + enum_set_meta_reverse_map_.destroy(); is_inited_ = false; used_subschema_id_ = MAX_NON_RESERVED_SUBSCHEMA_ID; reserved_ = 0; @@ -433,7 +365,7 @@ uint32_t ObSubSchemaCtx::get_subschema_count() const uint32_t subschema_count = 0; if (!is_inited_) { } else { - subschema_count = subschema_map_.size(); + subschema_count = subschema_array_.count(); } return subschema_count; } @@ -467,6 +399,17 @@ int ObSubSchemaCtx::get_subschema_id_from_fields(uint64_t udt_id, uint16_t &subs } return ret; } +int ObSubSchemaCtx::ensure_array_capacity(const uint16_t count) +{ + int ret = common::OB_SUCCESS; + if (OB_UNLIKELY(count >= subschema_array_.get_capacity()) && + OB_FAIL(subschema_array_.reserve(next_pow2(count)))) { + LOG_WARN("fail to reserve array capacity", K(ret), K(count), K_(subschema_array)); + } else if (OB_FAIL(subschema_array_.prepare_allocate(count))) { + LOG_WARN("fail to prepare allocate array", K(ret), K(count), K_(subschema_array)); + } + return ret; +} int ObSubSchemaCtx::set_subschema(uint16_t subschema_id, ObSubSchemaValue &value) { @@ -474,7 +417,7 @@ int ObSubSchemaCtx::set_subschema(uint16_t subschema_id, ObSubSchemaValue &value uint64_t key = subschema_id; ObSubSchemaValue tmp_value; ObSubSchemaReverseKey rev_key(value.type_, value.signature_); - if (OB_FAIL(subschema_map_.get_refactored(key, tmp_value))) { + if (OB_FAIL(get_subschema(key, tmp_value))) { if (OB_HASH_NOT_EXIST != ret) { LOG_WARN("failed to get subschema", K(ret), K(key), K(tmp_value), K(value)); } else if (value.type_ == ObSubSchemaType::OB_SUBSCHEMA_COLLECTION_TYPE) { @@ -484,14 +427,29 @@ int ObSubSchemaCtx::set_subschema(uint16_t subschema_id, ObSubSchemaValue &value if (OB_HASH_NOT_EXIST == ret) { // not exist ret = OB_SUCCESS; - LOG_INFO("add new subschema", K(ret), K(subschema_id), K(value)); - if (OB_FAIL(subschema_map_.set_refactored(key, value))) { - LOG_WARN("set subschema map failed", K(ret), K(subschema_id)); + LOG_INFO("add new subschema", K(ret), K(subschema_id), K(value), K(subschema_array_.count())); + if (OB_FAIL(ensure_array_capacity(subschema_id + 1))) { + LOG_WARN("fail to ensure array capacity", K(ret)); + } else if (FALSE_IT(subschema_array_.at(subschema_id) = value)) { } else if (OB_FAIL(subschema_reverse_map_.set_refactored(rev_key, key))) { - LOG_WARN("set subschema map failed", K(ret), K(rev_key)); - int tmp_ret = subschema_map_.erase_refactored(subschema_id); - if (tmp_ret != OB_SUCCESS) { - LOG_WARN("erase subschema map failed", K(ret), K(tmp_ret), K(subschema_id)); + if (OB_HASH_EXIST == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("set subschema map failed", K(ret), K(rev_key)); + subschema_array_.at(subschema_id).reset(); + } + } + if (OB_SUCC(ret) && value.type_ == OB_SUBSCHEMA_ENUM_SET_TYPE) { + const ObEnumSetMeta* enumset_meta = reinterpret_cast(value.value_); + ObEnumSetMetaReverseKey meta_rev_key(value.type_, enumset_meta); + if (OB_FAIL(enum_set_meta_reverse_map_.set_refactored(meta_rev_key, key))) { + if (OB_HASH_EXIST == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("set subschema map failed", K(ret), K(rev_key)); + subschema_array_.at(subschema_id).reset(); + subschema_reverse_map_.erase_refactored(rev_key); + } } } } @@ -504,8 +462,14 @@ int ObSubSchemaCtx::set_subschema(uint16_t subschema_id, ObSubSchemaValue &value int ObSubSchemaCtx::get_subschema(uint16_t subschema_id, ObSubSchemaValue &value) const { - uint64_t key = subschema_id; - return subschema_map_.get_refactored(key, value); + int ret = OB_SUCCESS; + if (OB_LIKELY(subschema_id < subschema_array_.count() && + subschema_array_.at(subschema_id).is_valid())) { + value = subschema_array_.at(subschema_id); + } else { + ret = OB_HASH_NOT_EXIST; + } + return ret; } int ObSubSchemaCtx::get_subschema_id(uint64_t value_signature, @@ -555,14 +519,12 @@ int ObSubSchemaCtx::get_subschema_id_by_typedef(const ObString &type_def, value.value_ = static_cast(buf); uint64_t key = tmp_subid; rev_key.str_signature_.assign_ptr(type_info.ptr(), type_info.length()); - if (OB_FAIL(subschema_map_.set_refactored(key, value))) { - LOG_WARN("set subschema map failed", K(ret), K(key)); + if (OB_FAIL(ensure_array_capacity(key + 1))) { + LOG_WARN("fail to ensure array capacity", K(ret)); + } else if (FALSE_IT(subschema_array_.at(key) = value)) { } else if (OB_FAIL(subschema_reverse_map_.set_refactored(rev_key, key))) { LOG_WARN("set subschema map failed", K(ret), K(rev_key)); - int tmp_ret = subschema_map_.erase_refactored(key); - if (tmp_ret != OB_SUCCESS) { - LOG_WARN("erase subschema map failed", K(ret), K(tmp_ret), K(key)); - } + subschema_array_.at(key).reset(); } } } @@ -625,5 +587,16 @@ int ObSubSchemaCtx::get_subschema_id_by_typedef(ObNestedType coll_type, return ret; } +int ObSubSchemaCtx::get_subschema_id(const ObSubSchemaType type, + const ObEnumSetMeta &meta, + uint16_t &subschema_id) const +{ + ObEnumSetMetaReverseKey rev_key(type, &meta); + uint64_t value = ObMaxSystemUDTSqlType; // init invalid subschema value + int ret = enum_set_meta_reverse_map_.get_refactored(rev_key, value); + subschema_id = value; + return ret; +} + } //sql } //oceanbase diff --git a/src/sql/engine/ob_subschema_ctx.h b/src/sql/engine/ob_subschema_ctx.h index dbd1da6d4..040d07a27 100644 --- a/src/sql/engine/ob_subschema_ctx.h +++ b/src/sql/engine/ob_subschema_ctx.h @@ -37,9 +37,20 @@ class ObSubSchemaValue { OB_UNIS_VERSION(1); public: - ObSubSchemaValue() : type_(OB_SUBSCHEMA_MAX_TYPE), signature_(0), value_(NULL) {} + ObSubSchemaValue() : type_(OB_SUBSCHEMA_MAX_TYPE), signature_(0), value_(NULL), + allocator_(NULL) {} ~ObSubSchemaValue() {} int deep_copy_value(const void *src_value, ObIAllocator &allocator); + static bool is_valid_type(ObSubSchemaType type) + { return type >= OB_SUBSCHEMA_UDT_TYPE && type < OB_SUBSCHEMA_MAX_TYPE; } + inline bool is_valid() const { return is_valid_type(type_); } + inline void reset() + { + type_ = OB_SUBSCHEMA_MAX_TYPE; + signature_ = 0; + value_ = NULL; + allocator_ = NULL; + } TO_STRING_KV(K_(type), K_(signature), KP_(value)); public: ObSubSchemaType type_; @@ -54,6 +65,7 @@ typedef int64_t (*ob_subschema_value_serialize_size)(void *value); typedef int (*ob_subschema_value_get_signature)(void *value, uint64_t &signature); typedef int (*ob_subschema_value_deep_copy)(const void *src_value, void *&dst_value, ObIAllocator &allocator); +typedef int (*ob_subschema_value_init)(void *&value, ObIAllocator &allocator); struct ObSubSchemaFuncs { @@ -63,33 +75,22 @@ struct ObSubSchemaFuncs ob_subschema_value_get_signature get_signature; ob_subschema_value_deep_copy deep_copy; - + ob_subschema_value_init init; }; -template -int subschema_value_serialize(void *value, char* buf, const int64_t buf_len, int64_t& pos) -{ - return OB_NOT_SUPPORTED; -} -template -int subschema_value_deserialize(void *value, const char* buf, const int64_t data_len, int64_t& pos) -{ - return OB_NOT_SUPPORTED; -} -template int64_t subschema_value_serialize_size(void *value) -{ - return OB_NOT_SUPPORTED; -} -template -int subschema_value_get_signature(void *value, uint64_t &signature) -{ - return OB_NOT_SUPPORTED; -} -template -int subschema_value_deep_copy(const void *src_value, void *&dst_value, ObIAllocator &allocator) -{ - return OB_NOT_SUPPORTED; -} +template +int subschema_value_serialize(void *value, char* buf, const int64_t buf_len, int64_t& pos); +template +int subschema_value_deserialize(void *value, const char* buf, const int64_t data_len, int64_t& pos); +template +int64_t subschema_value_serialize_size(void *value); +template +int subschema_value_get_signature(void *value, uint64_t &signature); +template +int subschema_value_deep_copy(const void *src_value, void *&dst_value, ObIAllocator &allocator); + +template +int subschema_value_init(void *&value, ObIAllocator &allocator); class ObSubSchemaReverseKey { @@ -124,14 +125,57 @@ class ObSubSchemaReverseKey ObString str_signature_; }; +class ObEnumSetMetaReverseKey +{ +public: + ObEnumSetMetaReverseKey() : type_(OB_SUBSCHEMA_MAX_TYPE), meta_(NULL) {} + ObEnumSetMetaReverseKey(const ObSubSchemaType type, const ObEnumSetMeta *meta) : + type_(type), meta_(meta) {} + ~ObEnumSetMetaReverseKey() {} + + inline uint64_t hash() const + { + uint64_t hash_val = 0; + if (OB_NOT_NULL(meta_)) { + hash_val = meta_->hash() + static_cast(type_); + } + return hash_val; + } + + inline int hash(uint64_t &res) const + { + res = hash(); + return OB_SUCCESS; + } + + inline bool operator==(const ObEnumSetMetaReverseKey &other) const + { + bool eq_ret = true; + if (other.type_ != this->type_) { + eq_ret = false; + } else if (meta_ == NULL || other.meta_ == NULL) { + eq_ret = (meta_ == other.meta_); + } else { + eq_ret = (*meta_ == *other.meta_); + } + return eq_ret; + } + + TO_STRING_KV(K_(type), KP_(meta)); + + ObSubSchemaType type_; + const ObEnumSetMeta *meta_; +}; + class ObSubSchemaCtx { OB_UNIS_VERSION(1); - typedef common::hash::ObHashMap ObSubSchemaMap; - // reverse map is used for confilict check and reverse search, reverse key is a signature from value; - typedef common::hash::ObHashMap ObSubSchemaReverseMap; static const uint16_t MAX_NON_RESERVED_SUBSCHEMA_ID = ObInvalidSqlType + 1; static const uint32_t SUBSCHEMA_BUCKET_NUM = 64; + typedef common::ObSEArray ObSubSchemaArray; + // reverse map is used for conflict check and reverse search, reverse key is a signature from value; + typedef common::hash::ObHashMap ObSubSchemaReverseMap; + typedef common::hash::ObHashMap ObEnumSetMetaReverseMap; public: ObSubSchemaCtx(ObIAllocator &allocator) : @@ -153,19 +197,28 @@ public: int set_subschema(uint16_t subschema_id, ObSubSchemaValue &value); int get_subschema(uint16_t subschema_id, ObSubSchemaValue &value) const; - ObSubSchemaMap &get_subschema_map() { return subschema_map_; } - const ObSubSchemaMap &get_subschema_map() const { return subschema_map_; } + ObSubSchemaArray &get_subschema_array() { return subschema_array_; } + const ObSubSchemaArray &get_subschema_array() const { return subschema_array_; } int get_subschema_id(uint64_t value_signature, ObSubSchemaType type, uint16_t &subschema_id) const; int get_subschema_id_by_typedef(ObNestedType coll_type, const ObDataType &elem_type, uint16_t &subschema_id); int get_subschema_id_by_typedef(ObNestedType coll_type, const ObDataType &elem_type, uint16_t &subschema_id) const; int get_subschema_id_by_typedef(const ObString &type_def, uint16_t &subschema_id); int get_subschema_id_by_typedef(const ObString &type_def, uint16_t &subschema_id) const; + int get_subschema_id(const ObSubSchemaType type, const ObEnumSetMeta &meta, + uint16_t &subschema_id) const; + void set_fields(const common::ObIArray *fields) { fields_ = fields; } ObIAllocator &get_allocator() { return allocator_; } TO_STRING_KV(K_(is_inited), K_(used_subschema_id), - K(subschema_map_.size()), K(subschema_reverse_map_.size())); + K(subschema_array_.count()), K(subschema_reverse_map_.size())); +private: + inline int ensure_array_capacity(const uint16_t count); + static bool is_type_info_subschema(const ObSubSchemaType type) + { + return type == OB_SUBSCHEMA_ENUM_SET_TYPE; + } private: bool is_inited_; @@ -174,8 +227,9 @@ private: const common::ObIArray *fields_; // resultset fields, no need to serialize ObIAllocator &allocator_; - ObSubSchemaMap subschema_map_; // subschema id mapping to subschema (e.g. udt meta) + ObSubSchemaArray subschema_array_; // subschema id (as array index) mapping to subschema (e.g. udt meta) ObSubSchemaReverseMap subschema_reverse_map_; // subschema type+signature (e.g. udt_id) mapping to subschema id + ObEnumSetMetaReverseMap enum_set_meta_reverse_map_; // subschema type + meta_ mapping to subschema id }; } diff --git a/src/sql/executor/ob_memory_tracker.cpp b/src/sql/executor/ob_memory_tracker.cpp new file mode 100644 index 000000000..a20b63d5a --- /dev/null +++ b/src/sql/executor/ob_memory_tracker.cpp @@ -0,0 +1,83 @@ +/** + * 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 LIB +#include "sql/executor/ob_memory_tracker.h" +#include "lib/rc/context.h" +#include "observer/omt/ob_tenant_config_mgr.h" +#include "share/rc/ob_tenant_base.h" + +using namespace oceanbase::lib; + +thread_local ObMemTracker ObMemTrackerGuard::mem_tracker_; + +void ObMemTrackerGuard::reset_try_check_tick() +{ + mem_tracker_.try_check_tick_ = 0; +} + +void ObMemTrackerGuard::dump_mem_tracker_info() +{ + int64_t tenant_mem_limit = lib::get_tenant_memory_limit(MTL_ID()); + int64_t mem_quota_pct = 100; + int64_t tree_mem_hold = 0; + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(MTL_ID())); + if (OB_UNLIKELY(tenant_config.is_valid())) { + mem_quota_pct = tenant_config->query_memory_limit_percentage; + } + if (nullptr != mem_tracker_.mem_context_) { + tree_mem_hold = mem_tracker_.mem_context_->tree_mem_hold(); + } + int64_t mem_limit = tenant_mem_limit / 100 * mem_quota_pct; + SQL_LOG(INFO, "dump memory tracker info", K(MTL_ID()), K(tenant_mem_limit), K(mem_limit), + K(tree_mem_hold)); +} + +void ObMemTrackerGuard::update_mem_limit() +{ + int ret = common::OB_SUCCESS; + int64_t tenant_mem_limit = lib::get_tenant_memory_limit(MTL_ID()); + int64_t mem_quota_pct = 100; + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(MTL_ID())); + if (OB_UNLIKELY(tenant_config.is_valid())) { + mem_quota_pct = tenant_config->query_memory_limit_percentage; + } + mem_tracker_.cache_mem_limit_ = tenant_mem_limit / 100 * mem_quota_pct; +} +int ObMemTrackerGuard::check_status() +{ + int ret = common::OB_SUCCESS; + if (nullptr != mem_tracker_.mem_context_) { + int64_t tree_mem_hold = mem_tracker_.mem_context_->tree_mem_hold(); + ++mem_tracker_.check_status_times_; + if (0 == mem_tracker_.cache_mem_limit_ + || (mem_tracker_.check_status_times_ % UPDATE_MEM_LIMIT_THRESHOLD == 0)) { + update_mem_limit(); + } + if (tree_mem_hold >= mem_tracker_.cache_mem_limit_) { + ret = OB_EXCEED_QUERY_MEM_LIMIT; + SQL_LOG(WARN, "Exceeded memory usage limit", K(ret), K(tree_mem_hold), + K(mem_tracker_.cache_mem_limit_)); + LOG_USER_ERROR(OB_EXCEED_QUERY_MEM_LIMIT, mem_tracker_.cache_mem_limit_, tree_mem_hold); + } + } + return ret; +} +int ObMemTrackerGuard::try_check_status(int64_t check_try_times) +{ + int ret = common::OB_SUCCESS; + if (nullptr != mem_tracker_.mem_context_ + && ((++mem_tracker_.try_check_tick_) % check_try_times == 0)) { + ret = check_status(); + } + return ret; +} diff --git a/src/sql/executor/ob_memory_tracker.h b/src/sql/executor/ob_memory_tracker.h new file mode 100644 index 000000000..c2e957511 --- /dev/null +++ b/src/sql/executor/ob_memory_tracker.h @@ -0,0 +1,79 @@ +/** + * 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_SQL_OB_MEMORY_TRACKER_H +#define OCEANBASE_SQL_OB_MEMORY_TRACKER_H + +#include "lib/alloc/alloc_func.h" + +namespace oceanbase +{ +namespace lib +{ +class MemoryContext; + +struct ObMemTracker +{ + ObMemTracker() : + cache_mem_limit_(0), check_status_times_(0), try_check_tick_(0), mem_context_(nullptr) + {} + void reset() + { + cache_mem_limit_ = 0; + check_status_times_ = 0; + try_check_tick_ = 0; + mem_context_ = nullptr; + } + + int64_t cache_mem_limit_; + uint16_t check_status_times_; + uint16_t try_check_tick_; + lib::MemoryContext *mem_context_; +}; + +class ObMemTrackerGuard +{ +public: + const static uint64_t DEFAULT_CHECK_STATUS_TRY_TIMES = 1024; + const static uint64_t UPDATE_MEM_LIMIT_THRESHOLD = 512; + ObMemTrackerGuard(lib::MemoryContext &mem_context) + { + mem_tracker_.reset(); + mem_tracker_.mem_context_ = &mem_context; + } + ~ObMemTrackerGuard() + { + mem_tracker_.reset(); + } + static void reset_try_check_tick(); + static void dump_mem_tracker_info(); + static void update_mem_limit(); + static int check_status(); + static int try_check_status(int64_t check_try_times = DEFAULT_CHECK_STATUS_TRY_TIMES); + +private: + static thread_local ObMemTracker mem_tracker_; +}; + +} // end namespace lib +} // end namespace oceanbase + +#define MEM_TRACKER_GUARD(mem_context) \ +oceanbase::lib::ObMemTrackerGuard mem_tracker_guard(mem_context); +#define RESET_TRY_CHECK_TICK \ +oceanbase::lib::ObMemTrackerGuard::reset_try_check_tick(); +#define CHECK_MEM_STATUS() \ +oceanbase::lib::ObMemTrackerGuard::check_status() +#define TRY_CHECK_MEM_STATUS(check_try_times) \ +oceanbase::lib::ObMemTrackerGuard::try_check_status(check_try_times) + +#endif /* OCEANBASE_SQL_OB_MEMORY_TRACKER_H */ diff --git a/src/sql/executor/ob_memory_tracker_wrapper.cpp b/src/sql/executor/ob_memory_tracker_wrapper.cpp new file mode 100644 index 000000000..9c6309658 --- /dev/null +++ b/src/sql/executor/ob_memory_tracker_wrapper.cpp @@ -0,0 +1,24 @@ +/** + * 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. + */ + +#include "sql/executor/ob_memory_tracker_wrapper.h" +#include "sql/executor/ob_memory_tracker.h" + +int check_mem_status() +{ + return oceanbase::lib::ObMemTrackerGuard::check_status(); +} + +int try_check_mem_status(int64_t check_try_times) +{ + return oceanbase::lib::ObMemTrackerGuard::try_check_status(check_try_times); +} diff --git a/src/sql/executor/ob_memory_tracker_wrapper.h b/src/sql/executor/ob_memory_tracker_wrapper.h new file mode 100644 index 000000000..cda7ba07e --- /dev/null +++ b/src/sql/executor/ob_memory_tracker_wrapper.h @@ -0,0 +1,29 @@ +/** + * 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_SQL_OB_MEMORY_TRACKER_WRAPPER_H +#define OCEANBASE_SQL_OB_MEMORY_TRACKER_WRAPPER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int check_mem_status(); +int try_check_mem_status(int64_t check_try_times); + +#ifdef __cplusplus +} +#endif + +#endif /* OCEANBASE_SQL_OB_MEMORY_TRACKER_WRAPPER_H */ diff --git a/src/sql/ob_spi.cpp b/src/sql/ob_spi.cpp index 09ed94612..4b73f2b49 100644 --- a/src/sql/ob_spi.cpp +++ b/src/sql/ob_spi.cpp @@ -734,6 +734,7 @@ int ObSPIService::cast_enum_set_to_string(ObExecContext &ctx, OX (result_type.set_meta(src.get_meta())); OX (result_type.set_accuracy(src.get_accuracy())); OX (c_expr->set_result_type(result_type)); + OX (c_expr->mark_enum_set_skip_build_subschema()); OZ (ObRawExprUtils::create_type_to_str_expr(*expr_factory, c_expr, out_expr, session_info, true)); CK (OB_NOT_NULL(out_expr)); OZ (ObSPIService::spi_calc_raw_expr(session_info, &(ctx.get_allocator()), out_expr, &result)); @@ -7572,6 +7573,16 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, OX (result_type.set_accuracy(current_type.at(i).get_accuracy())); } else { OX (result_type.set_accuracy(result_types[i].get_accuracy())); + if (OB_SUCC(ret) && result_type.is_enum_set_with_subschema()) { + ObObjMeta org_obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(result_type, + ctx->exec_ctx_->get_my_session(), + org_obj_meta))) { + LOG_WARN("fail to extrac enum set meta", K(ret)); + } else { + result_type.set_collation(org_obj_meta); + } + } } if (OB_SUCC(ret) && (result_type.is_blob() || result_type.is_blob_locator() || obj.is_blob() || obj.is_blob_locator()) && lib::is_oracle_mode()) { diff --git a/src/sql/ob_sql_utils.cpp b/src/sql/ob_sql_utils.cpp index 85408debd..22563f486 100644 --- a/src/sql/ob_sql_utils.cpp +++ b/src/sql/ob_sql_utils.cpp @@ -6149,7 +6149,8 @@ bool ObSQLUtils::check_need_disconnect_parser_err(const int ret_code) || OB_ERR_VIEW_SELECT_CONTAIN_QUESTIONMARK == ret_code || OB_ERR_NON_INT_LITERAL == ret_code || OB_ERR_PARSER_INIT == ret_code - || OB_NOT_SUPPORTED == ret_code)) { + || OB_NOT_SUPPORTED == ret_code + || OB_ALLOCATE_MEMORY_FAILED == ret_code)) { bret = false; } return bret; diff --git a/src/sql/optimizer/ob_join_order.cpp b/src/sql/optimizer/ob_join_order.cpp index 329944d09..970d52824 100644 --- a/src/sql/optimizer/ob_join_order.cpp +++ b/src/sql/optimizer/ob_join_order.cpp @@ -11425,6 +11425,9 @@ int ObJoinOrder::create_and_add_hash_path(const Path *left_path, LOG_WARN("failed to create subplan filter for join path", K(ret)); } else if (OB_FAIL(add_path(join_path))) { LOG_WARN("failed to add path", K(ret)); + } else if (CONNECT_BY_JOIN == join_type && + OB_FAIL(push_down_order_siblings(join_path, right_path))) { + LOG_WARN("push down order siblings by condition failed", K(ret)); } else { LOG_TRACE("succeed to create a hash join path", K(join_type), K(join_dist_algo), K(equal_join_conditions), K(other_join_conditions)); @@ -12768,7 +12771,7 @@ int ObJoinOrder::get_valid_path_info(const ObJoinOrder &left_tree, const bool both_access = ACCESS == left_tree.get_type() && ACCESS == right_tree.get_type(); const bool contain_fake_cte = left_paths.at(0)->contain_fake_cte() || right_paths.at(0)->contain_fake_cte(); if (CONNECT_BY_JOIN == path_info.join_type_) { - path_info.local_methods_ = NESTED_LOOP_JOIN; + path_info.local_methods_ = NESTED_LOOP_JOIN | HASH_JOIN; path_info.distributed_methods_ = DIST_PULL_TO_LOCAL | DIST_BASIC_METHOD; OPT_TRACE("connect by will use nl join"); OPT_TRACE("connect by will use pull to local / basic method"); diff --git a/src/sql/optimizer/ob_log_plan.cpp b/src/sql/optimizer/ob_log_plan.cpp index b9f82e6bd..14c54deb1 100644 --- a/src/sql/optimizer/ob_log_plan.cpp +++ b/src/sql/optimizer/ob_log_plan.cpp @@ -12207,7 +12207,7 @@ int ObLogPlan::generate_column_expr(ObRawExprFactory &expr_factory, column_item.expr_ = rowkey; if (OB_FAIL(rowkey->add_relation_id(stmt->get_table_bit_index(table_id)))) { LOG_WARN("add relation id to expr failed", K(ret)); - } else if (OB_FAIL(rowkey->formalize(NULL))) { + } else if (OB_FAIL(rowkey->formalize(optimizer_context_.get_session_info()))) { LOG_WARN("formalize rowkey failed", K(ret)); } else if (OB_FAIL(rowkey->pull_relation_id())) { LOG_WARN("failed to pullup relation ids", K(ret)); diff --git a/src/sql/optimizer/ob_optimizer_util.cpp b/src/sql/optimizer/ob_optimizer_util.cpp index 6b220969f..d16b87624 100644 --- a/src/sql/optimizer/ob_optimizer_util.cpp +++ b/src/sql/optimizer/ob_optimizer_util.cpp @@ -1889,7 +1889,8 @@ int ObOptimizerUtil::generate_rowkey_exprs(const ObDMLStmt *stmt, table_id, *table_schema, keys, - ordering))) { + ordering, + opt_ctx.get_session_info()))) { LOG_WARN("failed to get rowkeys raw expr", K(table_id), K(ref_table_id), K(ret)); } else { /*do nothing*/ } @@ -1901,7 +1902,8 @@ int ObOptimizerUtil::generate_rowkey_exprs(const ObDMLStmt* cstmt, uint64_t table_id, const ObTableSchema &index_table_schema, ObIArray &index_keys, - ObIArray &index_ordering) + ObIArray &index_ordering, + ObSQLSessionInfo *session) { int ret = OB_SUCCESS; ObDMLStmt *stmt = const_cast(cstmt); @@ -1927,7 +1929,8 @@ int ObOptimizerUtil::generate_rowkey_exprs(const ObDMLStmt* cstmt, //or other opt need to use different indexes in one logical plan, remember this problem. if (NULL != (raw_expr = stmt->get_column_expr_by_id(table_id, column_id))) { expr = static_cast(raw_expr); - } else if (OB_FAIL(generate_rowkey_expr(stmt, expr_factory, table_id, *column_schema, expr))) { + } else if (OB_FAIL(generate_rowkey_expr(stmt, expr_factory, table_id, *column_schema, expr, + session))) { LOG_WARN("failed to get row key expr", K(ret)); } else { /*do nothing*/ } @@ -7004,7 +7007,8 @@ int ObOptimizerUtil::add_cast_to_set_list(ObSQLSessionInfo *session_info, || OB_ISNULL(src_expr = stmt->get_select_item(idx).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected stmt", K(ret), K(stmts.at(i))); - } else if (ob_is_enumset_tc(src_expr->get_result_type().get_type())) { + } else if (ob_is_enumset_tc(src_expr->get_result_type().get_type()) + && !src_expr->is_enum_set_with_subschema()) { ObSysFunRawExpr *to_str_expr = NULL; if (src_expr->get_result_type() == res_type) { /*do nothing*/ @@ -8623,6 +8627,7 @@ int ObOptimizerUtil::generate_rowkey_expr(ObDMLStmt *stmt, const uint64_t &table_id, const ObColumnSchemaV2 &column_schema, ObColumnRefRawExpr *&rowkey, + ObSQLSessionInfo *session, ObIArray *column_items) { int ret = OB_SUCCESS; @@ -8655,7 +8660,7 @@ int ObOptimizerUtil::generate_rowkey_expr(ObDMLStmt *stmt, LOG_WARN("add column item to stmt failed", K(ret)); } else if (FALSE_IT(rowkey->clear_explicited_referece())) { /*do nothing*/ - } else if (OB_FAIL(rowkey->formalize(NULL))) { + } else if (OB_FAIL(rowkey->formalize(session))) { LOG_WARN("formalize rowkey failed", K(ret)); } else if (OB_FAIL(rowkey->pull_relation_id())) { LOG_WARN("failed to pullup relation ids", K(ret)); diff --git a/src/sql/optimizer/ob_optimizer_util.h b/src/sql/optimizer/ob_optimizer_util.h index fb1bcaa55..b9c17d398 100644 --- a/src/sql/optimizer/ob_optimizer_util.h +++ b/src/sql/optimizer/ob_optimizer_util.h @@ -411,7 +411,8 @@ public: uint64_t table_id, const share::schema::ObTableSchema &index_table_schema, common::ObIArray &index_keys, - common::ObIArray &index_ordering); + common::ObIArray &index_ordering, + ObSQLSessionInfo *session); static int build_range_columns(const ObDMLStmt *stmt, common::ObIArray &rowkeys, @@ -1425,6 +1426,7 @@ public: const uint64_t &table_id, const share::schema::ObColumnSchemaV2 &column_schema, ObColumnRefRawExpr *&rowkey, + ObSQLSessionInfo *session, common::ObIArray *column_items = NULL); static int check_contain_ora_rowscn_expr(const ObRawExpr *expr, bool &contains); diff --git a/src/sql/optimizer/ob_table_location.cpp b/src/sql/optimizer/ob_table_location.cpp index e7d20bc3f..44e04533b 100644 --- a/src/sql/optimizer/ob_table_location.cpp +++ b/src/sql/optimizer/ob_table_location.cpp @@ -4732,6 +4732,7 @@ int ValueItemExpr::deserialize(common::ObIAllocator &allocator, const char *buf, enum_set_values_ = static_cast(allocator.alloc(sizeof(ObString) * enum_set_values_cnt_)); CK(OB_NOT_NULL(enum_set_values_)); + MEMSET(enum_set_values_, 0, sizeof(ObString) * enum_set_values_cnt_); OB_UNIS_DECODE_ARRAY(enum_set_values_, enum_set_values_cnt_) } } diff --git a/src/sql/parser/ob_fast_parser.cpp b/src/sql/parser/ob_fast_parser.cpp index 732bf9f25..c9ae74dc7 100644 --- a/src/sql/parser/ob_fast_parser.cpp +++ b/src/sql/parser/ob_fast_parser.cpp @@ -98,18 +98,13 @@ int ObFastParser::parse(const common::ObString &stmt, return ret; } -ObFastParserBase::ObFastParserBase( - ObIAllocator &allocator, - const FPContext fp_ctx) : - no_param_sql_(nullptr), no_param_sql_len_(0), - param_num_(0), is_oracle_mode_(false), +ObFastParserBase::ObFastParserBase(ObIAllocator &allocator, const FPContext fp_ctx) : + no_param_sql_(nullptr), no_param_sql_len_(0), param_num_(0), is_oracle_mode_(false), is_batched_multi_stmt_split_on_(fp_ctx.enable_batched_multi_stmt_), - is_udr_mode_(fp_ctx.is_udr_mode_), - def_name_ctx_(fp_ctx.def_name_ctx_), - cur_token_begin_pos_(0), copy_begin_pos_(0), copy_end_pos_(0), - tmp_buf_(nullptr), tmp_buf_len_(0), last_escape_check_pos_(0), - param_node_list_(nullptr), tail_param_node_(nullptr), - cur_token_type_(INVALID_TOKEN), allocator_(allocator), + is_udr_mode_(fp_ctx.is_udr_mode_), def_name_ctx_(fp_ctx.def_name_ctx_), cur_token_begin_pos_(0), + copy_begin_pos_(0), copy_end_pos_(0), tmp_buf_(nullptr), tmp_buf_len_(0), + last_escape_check_pos_(0), try_check_tick_(0), param_node_list_(nullptr), + tail_param_node_(nullptr), cur_token_type_(INVALID_TOKEN), allocator_(allocator), found_insert_status_(NOT_FOUND_INSERT_TOKEN), values_token_pos_(0), parse_next_token_func_(nullptr), process_idf_func_(nullptr) { @@ -2234,6 +2229,12 @@ inline int ObFastParserBase::process_format_token() { return ret; } +inline int ObFastParserBase::try_check_status() +{ + return ((++try_check_tick_) % CHECK_STATUS_TRY_TIMES == 0) ? THIS_WORKER.check_status() : + common::OB_SUCCESS; +} + inline void ObFastParserBase::process_token() { if (NORMAL_TOKEN == cur_token_type_) { @@ -3025,15 +3026,12 @@ int ObFastParserMysql::parse_next_token() break; } } // end switch - - if (OB_FAIL(ret)) { - } else if (is_format_) { - if(OB_FAIL(process_format_token())) { - LOG_WARN("failed to process foramt token", K(ret)); - } + if (is_format_) { + OZ (process_format_token()); } else { OX (process_token()); } + OZ (try_check_status()); } // end while if (OB_SUCC(ret)) { // After processing the string, there are still parts that have not been saved, save directly @@ -3440,14 +3438,12 @@ int ObFastParserOracle::parse_next_token() } } // end switch last_ch = ch; - if (OB_FAIL(ret)) { - } else if (is_format_) { - if (OB_FAIL(process_format_token())) { - LOG_WARN("failed to process foramt token", K(ret)); - } + if (is_format_) { + OZ (process_format_token()); } else { OX (process_token()); } + OZ (try_check_status()); } // end while if (OB_SUCC(ret)) { // After processing the string, there are still parts that have not been saved, save directly diff --git a/src/sql/parser/ob_fast_parser.h b/src/sql/parser/ob_fast_parser.h index ac89d5d99..027a41769 100644 --- a/src/sql/parser/ob_fast_parser.h +++ b/src/sql/parser/ob_fast_parser.h @@ -245,6 +245,7 @@ protected: // this will not affect any correctness issues, and will make the code look better static const int64_t PARSER_NODE_SIZE = sizeof(ParseNode); static const int64_t FIEXED_PARAM_NODE_SIZE = PARSER_NODE_SIZE + sizeof(ParamList); + static const int64_t CHECK_STATUS_TRY_TIMES = 512; protected: /** @@ -644,6 +645,7 @@ protected: bool is_invalid_character(ObRawSql &raw_sql, int64_t pos, int64_t& skip_len); int extend_alloc_sql_buffer(); int process_format_token(); + int try_check_status(); protected: enum FoundInsertTokenStatus { @@ -665,6 +667,7 @@ protected: char *tmp_buf_; int64_t tmp_buf_len_; int64_t last_escape_check_pos_; + uint64_t try_check_tick_; public: ParamList *param_node_list_; ParamList *tail_param_node_; diff --git a/src/sql/parser/ob_memory_tracker_wrapper.cpp b/src/sql/parser/ob_memory_tracker_wrapper.cpp new file mode 100644 index 000000000..9c6309658 --- /dev/null +++ b/src/sql/parser/ob_memory_tracker_wrapper.cpp @@ -0,0 +1,24 @@ +/** + * 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. + */ + +#include "sql/executor/ob_memory_tracker_wrapper.h" +#include "sql/executor/ob_memory_tracker.h" + +int check_mem_status() +{ + return oceanbase::lib::ObMemTrackerGuard::check_status(); +} + +int try_check_mem_status(int64_t check_try_times) +{ + return oceanbase::lib::ObMemTrackerGuard::try_check_status(check_try_times); +} diff --git a/src/sql/parser/ob_memory_tracker_wrapper.h b/src/sql/parser/ob_memory_tracker_wrapper.h new file mode 100644 index 000000000..cda7ba07e --- /dev/null +++ b/src/sql/parser/ob_memory_tracker_wrapper.h @@ -0,0 +1,29 @@ +/** + * 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_SQL_OB_MEMORY_TRACKER_WRAPPER_H +#define OCEANBASE_SQL_OB_MEMORY_TRACKER_WRAPPER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int check_mem_status(); +int try_check_mem_status(int64_t check_try_times); + +#ifdef __cplusplus +} +#endif + +#endif /* OCEANBASE_SQL_OB_MEMORY_TRACKER_WRAPPER_H */ diff --git a/src/sql/parser/ob_parser.cpp b/src/sql/parser/ob_parser.cpp index 2b9bfbd9f..58c22bbf5 100644 --- a/src/sql/parser/ob_parser.cpp +++ b/src/sql/parser/ob_parser.cpp @@ -20,6 +20,7 @@ #include "pl/parser/ob_pl_parser.h" #include "lib/utility/ob_tracepoint.h" #include "lib/json/ob_json_print_utils.h" + using namespace oceanbase::pl; using namespace oceanbase::sql; using namespace oceanbase::common; diff --git a/src/sql/parser/parse_node.c b/src/sql/parser/parse_node.c index 82b7666e4..0ab33cd66 100644 --- a/src/sql/parser/parse_node.c +++ b/src/sql/parser/parse_node.c @@ -19,6 +19,7 @@ #include "sql/parser/parse_node_hash.h" #include "sql/parser/parse_define.h" #include "sql/parser/sql_parser_base.h" +#include "sql/executor/ob_memory_tracker_wrapper.h" extern const char *get_type_name(int type); #ifdef SQL_PARSER_COMPILATION @@ -173,30 +174,40 @@ int deep_copy_parse_node(void *malloc_pool, const ParseNode *src_node, ParseNode return ret; } +int __attribute__((weak)) check_mem_status() { return OB_PARSER_SUCCESS; } +int __attribute__((weak)) try_check_mem_status(int64_t check_try_times) { return OB_PARSER_SUCCESS; } + ParseNode *new_node(void *malloc_pool, ObItemType type, int num) { + int ret = OB_PARSER_SUCCESS; + const int64_t check_try_times = 1024; + ParseNode *node = NULL; // the mem alloced by parse_malloc has been memset; - ParseNode *node = (ParseNode *)parse_malloc(sizeof(ParseNode), malloc_pool); - if (OB_UNLIKELY(NULL == node)) { - (void)printf("malloc memory failed\n"); + if (OB_UNLIKELY((OB_PARSER_SUCCESS != (ret = try_check_mem_status(check_try_times))))) { + (void)printf("Exceeded memory usage limit\n"); } else { - node->type_ = type; - node->num_child_ = num; - node->value_ = INT64_MAX; - node->pl_str_off_ = -1; -#ifdef SQL_PARSER_COMPILATION - node->token_off_ = -1; - node->token_len_ = -1; -#endif - if (num > 0) { - int64_t alloc_size = sizeof(ParseNode *) * num ; - node->children_ = (ParseNode **)parse_malloc(alloc_size, malloc_pool); - if (OB_UNLIKELY(NULL == node->children_)) { - parse_free(node); - node = NULL; - } + node = (ParseNode *)parse_malloc(sizeof(ParseNode), malloc_pool); + if (OB_UNLIKELY(NULL == node)) { + (void)printf("malloc memory failed\n"); } else { - node->children_ = NULL; + node->type_ = type; + node->num_child_ = num; + node->value_ = INT64_MAX; + node->pl_str_off_ = -1; + #ifdef SQL_PARSER_COMPILATION + node->token_off_ = -1; + node->token_len_ = -1; + #endif + if (num > 0) { + int64_t alloc_size = sizeof(ParseNode *) * num ; + node->children_ = (ParseNode **)parse_malloc(alloc_size, malloc_pool); + if (OB_UNLIKELY(NULL == node->children_)) { + parse_free(node); + node = NULL; + } + } else { + node->children_ = NULL; + } } } return node; diff --git a/src/sql/parser/parse_node.h b/src/sql/parser/parse_node.h index 641379951..3656d6c45 100644 --- a/src/sql/parser/parse_node.h +++ b/src/sql/parser/parse_node.h @@ -390,6 +390,8 @@ extern ParseNode *new_terminal_node(void *malloc_pool, ObItemType type); extern ParseNode *new_list_node(void *malloc_pool, ObItemType node_tag, int capacity, int num, ...); extern int obpl_parser_check_stack_overflow(); +extern int check_mem_status(); +extern int try_check_mem_status(int64_t check_try_times); int get_deep_copy_size(const ParseNode *node, int64_t *size); int deep_copy_parse_node(void *malloc_pool, const ParseNode *src, ParseNode *dst); diff --git a/src/sql/parser/parser_utility.cpp b/src/sql/parser/parser_utility.cpp index 186e4f29b..6f6b04d22 100644 --- a/src/sql/parser/parser_utility.cpp +++ b/src/sql/parser/parser_utility.cpp @@ -12,6 +12,7 @@ #include "sql/parser/parser_utility.h" #include "lib/utility/ob_macro_utils.h" +#include "sql/executor/ob_memory_tracker.h" #include diff --git a/src/sql/plan_cache/ob_values_table_compression.cpp b/src/sql/plan_cache/ob_values_table_compression.cpp index de7bf6444..0264f4e88 100644 --- a/src/sql/plan_cache/ob_values_table_compression.cpp +++ b/src/sql/plan_cache/ob_values_table_compression.cpp @@ -510,10 +510,10 @@ int ObValuesTableCompression::resolve_params_for_values_clause(ObPlanCacheCtx &p ObExprTypeCtx type_ctx; ObSQLUtils::init_type_ctx(session, type_ctx); if (OB_FAIL(dummy_op.aggregate_result_type_for_merge(new_res_type, - &res_types.at(0), - res_types.count(), - false, - type_ctx))) { + &res_types.at(0), + res_types.count(), + false, + type_ctx))) { LOG_WARN("failed to aggregate result type for merge", K(ret)); } } diff --git a/src/sql/resolver/ddl/ob_alter_table_resolver.cpp b/src/sql/resolver/ddl/ob_alter_table_resolver.cpp index 3aec10256..573add156 100644 --- a/src/sql/resolver/ddl/ob_alter_table_resolver.cpp +++ b/src/sql/resolver/ddl/ob_alter_table_resolver.cpp @@ -5952,6 +5952,9 @@ int ObAlterTableResolver::alter_column_expr_in_part_expr( column_ref->set_data_type(dst_col_schema.get_data_type()); column_ref->set_accuracy(dst_col_schema.get_accuracy()); } + if (ob_is_enum_or_set_type(column_ref->get_result_type().get_type())) { + OZ (column_ref->set_enum_set_values(dst_col_schema.get_extended_type_info())); + } } else { for (int64_t i = 0; OB_SUCC(ret) && i < part_expr->get_param_count(); ++i) { ObRawExpr *sub_expr = part_expr->get_param_expr(i); diff --git a/src/sql/resolver/ddl/ob_create_table_resolver.cpp b/src/sql/resolver/ddl/ob_create_table_resolver.cpp index afe1f8df5..41ba66dde 100644 --- a/src/sql/resolver/ddl/ob_create_table_resolver.cpp +++ b/src/sql/resolver/ddl/ob_create_table_resolver.cpp @@ -2169,8 +2169,7 @@ int ObCreateTableResolver::resolve_table_elements_from_select(const ParseNode &p column_meta.set_type(ObLongTextType); } column.set_meta_type(column_meta); - if (column.is_enum_or_set() - || column.is_collection()) { // array column + if (column.is_collection()) { // array column if (OB_FAIL(column.set_extended_type_info(expr->get_enum_set_values()))) { LOG_WARN("set enum or set info failed", K(ret), K(*expr)); } @@ -2191,6 +2190,25 @@ int ObCreateTableResolver::resolve_table_elements_from_select(const ParseNode &p column.set_accuracy(expr->get_accuracy()); column.set_zero_fill(expr->get_result_flag() & ZEROFILL_FLAG); OZ (adjust_number_decimal_column_accuracy_within_max(column, lib::is_oracle_mode())); + if (OB_SUCC(ret) && column.is_enum_or_set()) { + if (expr->is_enum_set_with_subschema()) { + const ObEnumSetMeta *enum_set_meta = NULL; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_meta(expr->get_result_type(), + session_info_, + enum_set_meta))) { + LOG_WARN("fail to extrac enum set mete", K(ret)); + } else if (OB_FAIL(column.set_extended_type_info(*enum_set_meta->get_str_values()))) { + LOG_WARN("set enum or set info failed", K(ret), K(*expr)); + } else { + column.set_collation_type(enum_set_meta->get_collation_type()); + column.set_data_scale(SCALE_UNKNOWN_YET); + } + } else { + if (OB_FAIL(column.set_extended_type_info(expr->get_enum_set_values()))) { + LOG_WARN("set enum or set info failed", K(ret), K(*expr)); + } + } + } if (OB_SUCC(ret) && lib::is_oracle_mode() && expr->get_result_type().is_user_defined_sql_type()) { // udt column is varbinary used for null bitmap column.set_collation_type(CS_TYPE_BINARY); diff --git a/src/sql/resolver/ddl/ob_create_view_resolver.cpp b/src/sql/resolver/ddl/ob_create_view_resolver.cpp index aca98cf22..65fb87349 100644 --- a/src/sql/resolver/ddl/ob_create_view_resolver.cpp +++ b/src/sql/resolver/ddl/ob_create_view_resolver.cpp @@ -1746,6 +1746,7 @@ int ObCreateViewResolver::add_column_infos(const uint64_t tenant_id, } else if (OB_FAIL(fill_column_meta_infos(*expr, table_schema.get_charset_type(), table_schema.get_table_id(), + session_info, column, is_from_create_mview))) { LOG_WARN("failed to fill column meta infos", K(ret), K(column)); @@ -1766,6 +1767,7 @@ int ObCreateViewResolver::add_column_infos(const uint64_t tenant_id, int ObCreateViewResolver::fill_column_meta_infos(const ObRawExpr &expr, const ObCharsetType charset_type, const uint64_t table_id, + sql::ObSQLSessionInfo &session_info, ObColumnSchemaV2 &column, bool is_from_create_mview /* =false */) { @@ -1790,9 +1792,11 @@ int ObCreateViewResolver::fill_column_meta_infos(const ObRawExpr &expr, column.set_nullable(expr.get_result_type().is_not_null_for_read() ? false : true); } if (OB_FAIL(ret)) { - } else if ((column.is_enum_or_set() || column.is_collection()) + } else if (column.is_collection() && OB_FAIL(column.set_extended_type_info(expr.get_enum_set_values()))) { LOG_WARN("set enum or set info failed", K(ret), K(expr)); + } else if (OB_FAIL(adjust_enum_set_column_meta_info(expr, session_info, column))) { + LOG_WARN("fail to adjust enum set colum meta info", K(ret), K(expr)); } else if (OB_FAIL(adjust_string_column_length_within_max(column, lib::is_oracle_mode()))) { LOG_WARN("failed to adjust string column length within max", K(ret), K(expr)); } else if (OB_FAIL(adjust_number_decimal_column_accuracy_within_max(column, lib::is_oracle_mode()))) { diff --git a/src/sql/resolver/ddl/ob_create_view_resolver.h b/src/sql/resolver/ddl/ob_create_view_resolver.h index 11e8f4a5d..0489a34f5 100644 --- a/src/sql/resolver/ddl/ob_create_view_resolver.h +++ b/src/sql/resolver/ddl/ob_create_view_resolver.h @@ -77,6 +77,7 @@ public: static int fill_column_meta_infos(const ObRawExpr &expr, const ObCharsetType charset_type, const uint64_t table_id, + sql::ObSQLSessionInfo &session_info, ObColumnSchemaV2 &column, bool is_from_create_mview = false); static int resolve_column_default_value(const sql::ObSelectStmt *select_stmt, diff --git a/src/sql/resolver/ddl/ob_ddl_resolver.cpp b/src/sql/resolver/ddl/ob_ddl_resolver.cpp index 19e72db16..457da636f 100644 --- a/src/sql/resolver/ddl/ob_ddl_resolver.cpp +++ b/src/sql/resolver/ddl/ob_ddl_resolver.cpp @@ -7470,6 +7470,30 @@ int ObDDLResolver::adjust_number_decimal_column_accuracy_within_max(share::schem return ret; } +int ObDDLResolver::adjust_enum_set_column_meta_info(const ObRawExpr &expr, + sql::ObSQLSessionInfo &session_info, + share::schema::ObColumnSchemaV2 &column) +{ + int ret = OB_SUCCESS; + if (column.is_enum_or_set()) { + const ObEnumSetMeta *enum_set_meta = nullptr; + if (expr.is_enum_set_with_subschema()) { + if (OB_FAIL(ObRawExprUtils::extract_enum_set_meta(expr.get_result_type(), + &session_info, + enum_set_meta))) { + LOG_WARN("fail to extract enum set meta", K(ret), K(expr)); + } else { + column.set_meta_type(enum_set_meta->get_obj_meta()); + column.set_data_scale(-1); + OZ(column.set_extended_type_info(*enum_set_meta->get_str_values()), expr); + } + } else { + OZ(column.set_extended_type_info(expr.get_enum_set_values()), expr); + } + } + return ret; +} + int ObDDLResolver::resolve_range_partition_elements(ParseNode *node, const bool is_subpartition, const ObPartitionFuncType part_type, diff --git a/src/sql/resolver/ddl/ob_ddl_resolver.h b/src/sql/resolver/ddl/ob_ddl_resolver.h index 054c6fc2e..aea09c645 100644 --- a/src/sql/resolver/ddl/ob_ddl_resolver.h +++ b/src/sql/resolver/ddl/ob_ddl_resolver.h @@ -377,6 +377,10 @@ public: const bool is_oracle_mode); static int adjust_number_decimal_column_accuracy_within_max(share::schema::ObColumnSchemaV2 &column, const bool is_oracle_mode); + static int adjust_enum_set_column_meta_info(const ObRawExpr &expr, + sql::ObSQLSessionInfo &session_info, + share::schema::ObColumnSchemaV2 &column); + // { used for enum and set int fill_extended_type_info( const ParseNode &str_list_node, diff --git a/src/sql/resolver/dml/ob_default_value_utils.cpp b/src/sql/resolver/dml/ob_default_value_utils.cpp index f68087dbc..98468b47f 100644 --- a/src/sql/resolver/dml/ob_default_value_utils.cpp +++ b/src/sql/resolver/dml/ob_default_value_utils.cpp @@ -260,7 +260,7 @@ int ObDefaultValueUtils::resolve_default_expr(const ColumnItem &column_item, ObR LOG_WARN("params_.session_info_ is null", K(ret)); } else { default_func_expr->set_func_name(ObString::make_string(N_DEFAULT)); - default_func_expr->set_data_type(column_item.get_column_type()->get_type()); + default_func_expr->set_result_type(*column_item.get_column_type()); if (OB_FAIL(build_type_expr(&column_item, c_expr))) { LOG_WARN("fail to build type expr", K(ret)); } else if (OB_FAIL(default_func_expr->add_param_expr(c_expr))) { diff --git a/src/sql/resolver/dml/ob_hint.cpp b/src/sql/resolver/dml/ob_hint.cpp index 59f6a6482..acfb70223 100644 --- a/src/sql/resolver/dml/ob_hint.cpp +++ b/src/sql/resolver/dml/ob_hint.cpp @@ -930,6 +930,11 @@ bool ObOptParamHint::is_param_val_valid(const OptParamType param_type, const ObO || 0 == val.get_varchar().case_compare("false")); break; } + case ENABLE_ENUM_SET_SUBSCHEMA: { + is_valid = val.is_varchar() && (0 == val.get_varchar().case_compare("true") + || 0 == val.get_varchar().case_compare("false")); + break; + } default: LOG_TRACE("invalid opt param val", K(param_type), K(val)); break; diff --git a/src/sql/resolver/dml/ob_hint.h b/src/sql/resolver/dml/ob_hint.h index 346c28ba4..093dc2102 100644 --- a/src/sql/resolver/dml/ob_hint.h +++ b/src/sql/resolver/dml/ob_hint.h @@ -188,6 +188,7 @@ struct ObOptParamHint DEF(PARTITION_INDEX_DIVE_LIMIT,) \ DEF(OB_TABLE_ACCESS_POLICY,) \ DEF(PARTITION_WISE_PLAN_ENABLED,) \ + DEF(ENABLE_ENUM_SET_SUBSCHEMA,) \ DECLARE_ENUM(OptParamType, opt_param, OPT_PARAM_TYPE_DEF, static); diff --git a/src/sql/resolver/dml/ob_select_resolver.cpp b/src/sql/resolver/dml/ob_select_resolver.cpp index ab39eb989..9d72ce370 100644 --- a/src/sql/resolver/dml/ob_select_resolver.cpp +++ b/src/sql/resolver/dml/ob_select_resolver.cpp @@ -36,6 +36,7 @@ #include "common/ob_smart_call.h" #include "sql/engine/expr/ob_expr_regexp_context.h" #include "sql/engine/expr/ob_json_param_type.h" +#include "sql/executor/ob_memory_tracker.h" namespace oceanbase { using namespace common; @@ -1511,7 +1512,10 @@ int ObSelectResolver::resolve(const ParseNode &parse_tree) int ret = OB_SUCCESS; ObSelectStmt *select_stmt = NULL; bool is_stack_overflow = false; - if (NULL == (select_stmt = create_stmt())) { + const int64_t check_try_times = 32; + if (OB_UNLIKELY((OB_SUCCESS != (ret = TRY_CHECK_MEM_STATUS(check_try_times))))) { + LOG_WARN("Exceeded memory usage limit", K(ret)); + } else if (NULL == (select_stmt = create_stmt())) { ret = OB_SQL_RESOLVER_NO_MEMORY; LOG_WARN("failed to create select stmt"); } else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) { @@ -5468,6 +5472,8 @@ int ObSelectResolver::resolve_column_ref_in_all_namespace( real_ref_expr, exec_param))) { LOG_WARN("failed to get exec param expr", K(ret)); + } else if (OB_FAIL(exec_param->formalize(session_info_))) { + LOG_WARN("fail to formalize exec param", K(ret)); } else { /// succeed to resolve the correlated column, do the replace here real_ref_expr = exec_param; diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index ad01ebfd6..c4fc344d5 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -428,7 +428,7 @@ int ObRawExpr::deduce_type(const ObSQLSessionInfo *session_info, ObRawExprDeduceType expr_deducer(session_info, solidify_session_vars, local_vars, local_var_id); expr_deducer.set_expr_factory(expr_factory_); if (OB_FAIL(expr_deducer.deduce(*this))) { - if (session_info->is_varparams_sql_prepare() && + if (OB_NOT_NULL(session_info) && session_info->is_varparams_sql_prepare() && OB_ERR_INVALID_COLUMN_NUM != ret && OB_ERR_TOO_MANY_VALUES != ret) { ret = OB_SUCCESS; diff --git a/src/sql/resolver/expr/ob_raw_expr.h b/src/sql/resolver/expr/ob_raw_expr.h index a27658cf9..6e4de3b97 100644 --- a/src/sql/resolver/expr/ob_raw_expr.h +++ b/src/sql/resolver/expr/ob_raw_expr.h @@ -44,6 +44,7 @@ #include "sql/engine/expr/ob_expr_join_filter.h" #include "sql/engine/expr/ob_expr_calc_partition_id.h" #include "sql/resolver/dml/ob_raw_expr_sets.h" +#include "sql/executor/ob_memory_tracker.h" namespace oceanbase { namespace share @@ -4961,11 +4962,13 @@ private: class ObRawExprFactory { public: + const static uint64_t CHECK_STATUS_TRY_TIMES = 1024; explicit ObRawExprFactory(common::ObIAllocator &alloc) : allocator_(alloc), expr_store_(alloc), is_called_sql_(true), - proxy_(nullptr) + proxy_(nullptr), + try_check_tick_(0) { } ObRawExprFactory(ObRawExprFactory &expr_factory) : allocator_(expr_factory.allocator_), @@ -5030,10 +5033,23 @@ public: return ret; } + inline int try_check_status() + { + return ((++try_check_tick_) % CHECK_STATUS_TRY_TIMES == 0) + ? CHECK_MEM_STATUS() + : common::OB_SUCCESS; + } + template int create_raw_expr(ObItemType expr_type, ExprType *&raw_expr) { - return create_raw_expr_inner(expr_type, raw_expr); + int ret = common::OB_SUCCESS; + if (OB_FAIL(try_check_status())) { + SQL_RESV_LOG(WARN, "Exceeded memory usage limit", K(ret)); + } else if (OB_FAIL(create_raw_expr_inner(expr_type, raw_expr))) { + SQL_RESV_LOG(WARN, "failed to create raw expr", K(ret)); + } + return ret; } @@ -5062,6 +5078,7 @@ private: bool is_called_sql_; //if not null, raw_expr is create by pl resolver ObRawExprFactory *proxy_; + int64_t try_check_tick_; private: DISALLOW_COPY_AND_ASSIGN(ObRawExprFactory); }; 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 9aff18bd1..6cae02557 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp @@ -60,6 +60,9 @@ int ObRawExprDeduceType::visit(ObConstRawExpr &expr) K(expr.get_expr_obj_meta().get_type()), K(ret)); } + if (expr.is_enum_set_with_subschema()) { + expr.reset_enum_set_meta_state(); + } expr.set_meta_type(expr.get_expr_obj_meta()); //expr.set_meta_type(expr.get_value().get_meta()); expr.set_param(expr.get_value()); @@ -72,7 +75,9 @@ int ObRawExprDeduceType::visit(ObConstRawExpr &expr) } //add local vars to expr if (OB_SUCC(ret)) { - if (solidify_session_vars_) { + if (OB_FAIL(build_subschema_for_enum_set_type(expr))) { + LOG_WARN("fail to build subschema for enum set type", K(ret)); + } else if (solidify_session_vars_) { if (OB_FAIL(expr.set_local_session_vars(NULL, my_session_, local_vars_id_))) { LOG_WARN("fail to set session vars", K(ret), K(expr)); } @@ -202,6 +207,8 @@ int ObRawExprDeduceType::visit(ObColumnRefRawExpr &expr) LOG_WARN("failed to construct collection attr expr", K(ret)); } } + } else if (OB_FAIL(build_subschema_for_enum_set_type(expr))) { + LOG_WARN("fail to build subschema for enum set type", K(ret), K(expr)); } if (OB_SUCC(ret)) { @@ -535,7 +542,7 @@ int ObRawExprDeduceType::calc_result_type(ObNonTerminalRawExpr &expr, // casted into number. However, this requirements are not remembered in the input_types // for the avg() expression but as the calc_type for the input expression itself. This // demands that we set the calculation type here. - for (int64_t i = 0; i < types.count(); ++i) { + for (int64_t i = 0; i < types.count() && OB_SUCC(ret); ++i) { types.at(i).set_calc_meta(types.at(i)); if (lib::is_mysql_mode() && types.at(i).is_double()) { const ObPrecision p = types.at(i).get_precision(); @@ -545,6 +552,20 @@ int ObRawExprDeduceType::calc_result_type(ObNonTerminalRawExpr &expr, (s >= 0 && s <= OB_MAX_DOUBLE_FLOAT_SCALE && p >= s)) { types.at(i).set_calc_accuracy(types.at(i).get_accuracy()); } + } else if (ob_is_enumset_tc(types.at(i).get_type())) { + ObObjMeta param_obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(types.at(i), + my_session_, + param_obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + // restore enum/set collation there, the expr type deduce is not aware of enum/set + // subschema meta. + types.at(i).set_collation(param_obj_meta); + types.at(i).set_calc_collation_type(param_obj_meta.get_collation_type()); + types.at(i).set_calc_collation_level(param_obj_meta.get_collation_level()); + types.at(i).reset_enum_set_meta_state(); + } } } if (ignore_scale_adjust_for_decimal_int(expr.get_expr_type())) { @@ -602,6 +623,7 @@ int ObRawExprDeduceType::calc_result_type(ObNonTerminalRawExpr &expr, break; } // end switch } + if (OB_NOT_IMPLEMENT == ret) { if (OB_FAIL(calc_result_type_with_const_arg(expr, types, type_ctx, op, result_type, row_dimension))) { if (OB_NOT_IMPLEMENT == ret) { @@ -1455,6 +1477,16 @@ int ObRawExprDeduceType::set_json_agg_result_type(ObAggFunRawExpr &expr, ObExprR switch (expr.get_expr_type()) { case T_FUN_JSON_ARRAYAGG: { + ObRawExpr *param_expr1 = NULL; + if (OB_UNLIKELY(expr.get_real_param_count() != 1) || + OB_ISNULL(param_expr1 = expr.get_param_expr(0))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("get unexpected error", K(ret), K(expr.get_param_count()), + K(expr.get_real_param_count()), K(expr)); + } else { + ObExprResType& expr_type1 = const_cast(param_expr1->get_result_type()); + need_add_cast = expr_type1.is_enum_set_with_subschema(); + } result_type.set_json(); result_type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObJsonType]).get_length()); expr.set_result_type(result_type); @@ -1856,10 +1888,14 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) } } else if (ob_is_json(obj_type) || ob_is_string_type(obj_type) || ob_is_enumset_tc(obj_type)) { + // string to double no need scale information result_type.set_double(); // todo jiuren // todo blob and text@hanhui - if (result_type.get_scale() >= 0) { + if (ob_is_enumset_tc(obj_type)) { + result_type.set_scale(SCALE_UNKNOWN_YET); + result_type.set_precision(PRECISION_UNKNOWN_YET); + } else if (result_type.get_scale() >= 0) { scale_increment_recover = result_type.get_scale(); result_type.set_scale(static_cast(result_type.get_scale() + scale_increment)); } @@ -2116,7 +2152,18 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) const_cast(param_expr->get_result_type()).set_calc_type(ObIntType); } } else if (i == 1) { - result_type.set_collation_type(param_expr->get_result_type().get_collation_type()); + if (param_expr->is_enum_set_with_subschema()) { + ObObjMeta org_obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(param_expr->get_result_type(), + my_session_, + org_obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + result_type.set_collation_type(org_obj_meta.get_collation_type()); + } + } else { + result_type.set_collation_type(param_expr->get_result_type().get_collation_type()); + } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected NULL", K(expr.get_param_count()), K(ret)); @@ -2162,7 +2209,18 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) result_type.set_blob(); result_type.set_length(OB_MAX_LONGTEXT_LENGTH); result_type.set_collation_level(CS_LEVEL_IMPLICIT); - result_type.set_collation_type(param_expr1->get_result_type().get_collation_type()); + if (param_expr1->is_enum_set_with_subschema()) { + ObObjMeta org_obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(param_expr1->get_result_type(), + my_session_, + org_obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + result_type.set_collation_type(org_obj_meta.get_collation_type()); + } + } else { + result_type.set_collation_type(param_expr1->get_result_type().get_collation_type()); + } if (lib::is_oracle_mode()) { const_cast(param_expr2->get_result_type()).set_calc_type(ObNumberType); } else { @@ -2677,6 +2735,19 @@ int ObRawExprDeduceType::visit(ObSysFunRawExpr &expr) } else {/*do nothing*/} } } + // There are some exprs such as nullif, column convert, etc. that require build subschema for + // enum or set types + if (OB_SUCC(ret) && ob_is_enumset_tc(expr.get_data_type())) { + const ObItemType expr_type = expr.get_expr_type(); + if (T_FUN_SYS_REMOVE_CONST == expr_type || + T_FUN_SYS_CAST == expr_type || + T_FUN_SYS_WRAPPER_INNER == expr_type || + T_FUN_SYS_DEFAULT == expr_type) { + // skip some inner added expr, their result type meta should be determined by the args. + } else if (OB_FAIL(build_subschema_for_enum_set_type(expr))) { + LOG_WARN("fail to build subschema for enum set type", K(ret), K(expr)); + } + } CK(OB_NOT_NULL(my_session_)); if (OB_SUCC(ret)) { // Casting from bit to binary depends on this flag to be compatible with MySQL, @@ -3526,8 +3597,12 @@ int ObRawExprDeduceType::set_agg_min_max_result_type(ObAggFunRawExpr &expr, const ObExprResType& res_type = child_expr->get_result_type(); result_type.set_varchar(); result_type.set_length(res_type.get_length()); - result_type.set_collation_type(res_type.get_collation_type()); - result_type.set_collation_level(CS_LEVEL_IMPLICIT); + ObObjMeta obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(res_type, my_session_, obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + result_type.set_collation(obj_meta); + } expr.set_result_type(result_type); } else { // keep same with default path @@ -3883,6 +3958,27 @@ int ObRawExprDeduceType::add_implicit_cast(ObAggFunRawExpr &parent, if (skip_cast_expr(parent, i)) { // do nothing //兼容oracle行为,regr_sxx和regr_syy只需在计算的参数加cast,regr_sxy行为和regr_syy一致,比较诡异,暂时兼容 + } else if ((parent.get_expr_type() == T_FUN_JSON_OBJECTAGG || + parent.get_expr_type() == T_FUN_JSON_ARRAYAGG) && + child_ptr->get_result_type().is_enum_set_with_subschema()) { + ObExprResType result_type(alloc_); + result_type.set_varchar(); + result_type.set_length(child_ptr->get_result_type().get_length()); + ObObjMeta obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(child_ptr->get_result_type(), + my_session_, + obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + result_type.set_collation(obj_meta); + } + result_type.set_calc_meta(result_type.get_obj_meta()); + if (OB_FAIL(ret)) { + } else if (OB_FAIL(try_add_cast_expr(parent, i, result_type, cast_mode))) { + LOG_WARN("try_add_cast_expr failed", K(ret)); + } else { + LOG_DEBUG("add_implicit_cast for ObAggFunRawExpr", K(i), K(res_type), KPC(child_ptr)); + } } else if ((parent.get_expr_type() == T_FUN_REGR_SXX && i == 0) || (parent.get_expr_type() == T_FUN_REGR_SYY && i == 1) || (parent.get_expr_type() == T_FUN_REGR_SXY && i == 1) || @@ -4014,6 +4110,10 @@ int ObRawExprDeduceType::try_add_cast_expr_above_for_deduce_type(ObRawExpr &expr || ob_is_decimal_int_tc(dst_type.get_calc_meta().get_type())) && dst_type.get_calc_scale() == -1) { cast_dst_type.set_accuracy(child_res_type.get_accuracy()); + if (child_res_type.is_enum_or_set()) { + cast_dst_type.set_precision(PRECISION_UNKNOWN_YET); + cast_dst_type.set_scale(SCALE_UNKNOWN_YET); + } } else if (lib::is_oracle_mode() && ob_is_decimal_int_tc(dst_type.get_calc_meta().get_type()) && dst_type.get_calc_scale() == SCALE_UNKNOWN_YET) { @@ -4250,5 +4350,42 @@ int ObRawExprDeduceType::try_replace_cast_with_questionmark_ora(ObRawExpr &paren } return ret; } + +int ObRawExprDeduceType::build_subschema_for_enum_set_type(ObRawExpr &expr) +{ + int ret = OB_SUCCESS; + ObSQLSessionInfo *session = NULL; + ObExecContext *exec_ctx = NULL; + uint16_t subschema_id = 0; + if (!expr.get_result_type().is_enum_or_set()) { + // Non-enum or set types do not need to build subschema + } else if (expr.skip_build_subschema_for_enumset() || !expr.is_called_in_sql()) { + // skiping pl scenario, because compilation and calling do not share the same plan ctx + // the subschema has been built, do nothing + } else if (OB_ISNULL(session = const_cast(my_session_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session can not be null", K(ret)); + } else if (OB_ISNULL(exec_ctx = session->get_cur_exec_ctx()) || + OB_ISNULL(exec_ctx->get_physical_plan_ctx()) || + OB_NOT_NULL(exec_ctx->get_physical_plan_ctx()->get_phy_plan())) { + // exec_ctx may be null in ddl generated column scenarios, and it all use column_convert, + // so the subschema meta build for this scenario is skipped + LOG_INFO("exec ctx is null", K(ret), K(*session)); + } else if (!exec_ctx->support_enum_set_type_subschema(*session)) { + } else if (OB_UNLIKELY(expr.get_enum_set_values().empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("str values for enum set expr is empty", K(ret), K(expr.get_enum_set_values())); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_type_info( + expr.get_result_type().get_obj_meta(), + expr.get_enum_set_values(), + subschema_id))) { + LOG_WARN("failed to get subschema id by udt id", K(ret)); + } else { + expr.set_subschema_id(subschema_id); + expr.mark_enum_set_with_subschema(); + } + return ret; +} + } // namespace sql } // namespace oceanbase 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 572e914f3..6a414ef64 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.h +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.h @@ -155,6 +155,7 @@ private: int try_replace_casts_with_questionmarks_ora(ObRawExpr *row_expr); int try_replace_cast_with_questionmark_ora(ObRawExpr &parent, ObRawExpr *cast_expr, int param_idx); + int build_subschema_for_enum_set_type(ObRawExpr &expr); private: const sql::ObSQLSessionInfo *my_session_; common::ObArenaAllocator alloc_; diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index 456274469..8f742b329 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -42,6 +42,8 @@ #include "sql/resolver/dml/ob_dml_resolver.h" #include "sql/resolver/dml/ob_select_resolver.h" #include "sql/resolver/expr/ob_raw_expr_deduce_type.h" +#include "sql/resolver/dml/ob_inlist_resolver.h" +#include "lib/enumset/ob_enum_set_meta.h" namespace oceanbase { @@ -1093,7 +1095,7 @@ int ObRawExprUtils::resolve_udf_param_exprs(ObResolverParams ¶ms, OX (mode = static_cast(iparam->get_mode())); if (OB_SUCC(ret) && lib::is_mysql_mode()) { bool need_wrap = false; - OZ (ObRawExprUtils::need_wrap_to_string(udf_raw_expr->get_param_expr(i)->get_result_type().get_type(), + OZ (ObRawExprUtils::need_wrap_to_string(udf_raw_expr->get_param_expr(i)->get_result_type(), iparam->get_pl_data_type().get_obj_type(), true, need_wrap)); @@ -4374,26 +4376,30 @@ int ObRawExprUtils::create_cast_expr(ObRawExprFactory &expr_factory, need_extra_cast_for_dst_type); // extra cast expr: cast non-utf8 to utf8 + ObExprResType extra_type; ObSysFunRawExpr *extra_cast = NULL; if (need_extra_cast_for_src_type) { - ObExprResType src_type_utf8; - OZ(setup_extra_cast_utf8_type(src_type, src_type_utf8)); - OZ(create_real_cast_expr(expr_factory, src_expr, src_type_utf8, extra_cast, session)); + OZ(setup_extra_cast_utf8_type(src_type, extra_type)); + OZ(create_real_cast_expr(expr_factory, src_expr, extra_type, extra_cast, session)); OZ(create_real_cast_expr(expr_factory, extra_cast, dst_type, func_expr, session)); } else if (need_extra_cast_for_dst_type) { - ObExprResType dst_type_utf8; - OZ(setup_extra_cast_utf8_type(dst_type, dst_type_utf8)); - OZ(create_real_cast_expr(expr_factory, src_expr, dst_type_utf8, extra_cast, session)); + OZ(setup_extra_cast_utf8_type(dst_type, extra_type)); + OZ(create_real_cast_expr(expr_factory, src_expr, extra_type, extra_cast, session)); OZ(create_real_cast_expr(expr_factory, extra_cast, dst_type, func_expr, session)); } else if (src_type.get_type() == ObExtendType && src_type.get_udt_id() == T_OBJ_XML && dst_type.is_character_type() && src_expr->is_called_in_sql()) { // pl xmltype -> sql xmltype -> char type is supported only in sql scenario - ObExprResType sql_udt_type; - sql_udt_type.set_sql_udt(ObXMLSqlType); // set subschema id - sql_udt_type.set_udt_id(T_OBJ_XML); - OZ(create_real_cast_expr(expr_factory, src_expr, sql_udt_type, extra_cast, session)); + extra_type.set_sql_udt(ObXMLSqlType); // set subschema id + extra_type.set_udt_id(T_OBJ_XML); + OZ(create_real_cast_expr(expr_factory, src_expr, extra_type, extra_cast, session)); + OZ(create_real_cast_expr(expr_factory, extra_cast, dst_type, func_expr, session)); + } else if (OB_FAIL(need_extra_cast_for_enumset(src_type, dst_type, session, extra_type, + need_extra_cast_for_src_type))) { + LOG_WARN("fail to check need extra for enumset", K(ret), K(src_type), K(dst_type)); + } else if (need_extra_cast_for_src_type) { + OZ(create_real_cast_expr(expr_factory, src_expr, extra_type, extra_cast, session)); OZ(create_real_cast_expr(expr_factory, extra_cast, dst_type, func_expr, session)); } else { OZ(create_real_cast_expr(expr_factory, src_expr, dst_type, func_expr, session)); @@ -4443,7 +4449,8 @@ void ObRawExprUtils::need_extra_cast(const ObExprResType &src_type, need_extra_cast_for_src_type = true; } } else if (nonstr_to_str) { - if (CHARSET_BINARY != dst_cs && ObCharset::get_default_charset() != dst_cs && !src_type.is_bit()) { + if (CHARSET_BINARY != dst_cs && ObCharset::get_default_charset() != dst_cs && !src_type.is_bit() + && !src_type.is_enum_set_with_subschema()) { need_extra_cast_for_dst_type = true; } } @@ -4940,7 +4947,7 @@ int ObRawExprUtils::create_type_to_str_expr(ObRawExprFactory &expr_factory, LOG_ERROR("allocate expr operator failed", K(ret)); } else { out_expr->set_func_name(ObString::make_string(func_name)); - if (ob_is_large_text(dst_type)) { + if (ob_is_large_text(dst_type) || dst_type == ObCharType) { out_expr->set_extra(static_cast(dst_type)); } else { out_expr->set_extra(0); @@ -4950,8 +4957,13 @@ int ObRawExprUtils::create_type_to_str_expr(ObRawExprFactory &expr_factory, ObConstRawExpr *col_accuracy_expr = NULL; if (OB_SUCC(ret)) { ObString str_col_accuracy; - if (OB_FAIL(build_const_string_expr(expr_factory, ObVarcharType, str_col_accuracy, - src_expr->get_collation_type(), col_accuracy_expr))) { + ObObjMeta obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(src_expr->get_result_type(), + session_info, + obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else if (OB_FAIL(build_const_string_expr(expr_factory, ObVarcharType, str_col_accuracy, + obj_meta.get_collation_type(), col_accuracy_expr))) { LOG_WARN("fail to build type expr", K(ret)); } else if (OB_ISNULL(col_accuracy_expr)) { ret = OB_ERR_UNEXPECTED; @@ -4960,6 +4972,7 @@ int ObRawExprUtils::create_type_to_str_expr(ObRawExprFactory &expr_factory, col_accuracy_expr->set_collation_type(src_expr->get_collation_type()); col_accuracy_expr->set_collation_level(src_expr->get_collation_level()); col_accuracy_expr->set_accuracy(src_expr->get_accuracy()); + col_accuracy_expr->set_scale(SCALE_UNKNOWN_YET); } } @@ -5329,7 +5342,19 @@ int ObRawExprUtils::build_column_conv_expr(ObRawExprFactory &expr_factory, } CK(session_info); if (OB_SUCC(ret)) { - if (col_ref.is_fulltext_column() || + ObObjMeta obj_meta = col_ref.get_result_meta(); + ObAccuracy accuracy = col_ref.get_accuracy(); + if (col_ref.is_enum_set_with_subschema()) { + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(col_ref.get_result_type(), + session_info, + obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + accuracy.set_scale(SCALE_UNKNOWN_YET); + } + } + if (OB_FAIL(ret)) { + } else if (col_ref.is_fulltext_column() || col_ref.is_spatial_generated_column() || col_ref.is_multivalue_generated_column() || col_ref.is_multivalue_generated_array_column() || @@ -5339,9 +5364,9 @@ int ObRawExprUtils::build_column_conv_expr(ObRawExprFactory &expr_factory, } else if (OB_FAIL(build_column_conv_expr(session_info, expr_factory, col_ref.get_data_type(), - col_ref.get_collation_type(), + obj_meta.get_collation_type(), // accuracy used as udt id for udt columns - col_ref.get_accuracy().get_accuracy(), + accuracy.get_accuracy(), !col_ref.is_not_null_for_write(), &column_conv_info, &col_ref.get_enum_set_values(), @@ -7145,6 +7170,8 @@ int ObRawExprUtils::init_column_expr(const ObColumnSchemaV2 &column_schema, ObCo if (OB_SUCC(ret) && (column_schema.is_enum_or_set() || column_schema.is_collection())) { if (OB_FAIL(column_expr.set_enum_set_values(column_schema.get_extended_type_info()))) { LOG_WARN("failed to set enum set values", K(ret)); + } else { + column_expr.reset_enum_set_meta_state(); } } if (OB_SUCC(ret) && column_schema.is_xmltype()) { @@ -7261,11 +7288,14 @@ int ObRawExprUtils::extract_int_value(const ObRawExpr *expr, int64_t &val) return ret; } -int ObRawExprUtils::need_wrap_to_string(ObObjType param_type, ObObjType calc_type, const bool is_same_type_need, bool &need_wrap) +int ObRawExprUtils::need_wrap_to_string(const ObExprResType &src_res_type, + ObObjType calc_type, + const bool is_same_type_need, bool &need_wrap) { //TODO(yaoying.yyy):这个函数需要在case中覆盖 且ObExtendType 和ObUnknownType int ret = OB_SUCCESS; need_wrap = false; + ObObjType param_type = src_res_type.get_type(); if (!ob_is_enumset_tc(param_type)) { //输入参数不是enum 类型 则不需要转换 } else if (param_type == calc_type && (!is_same_type_need)) { @@ -7319,7 +7349,8 @@ int ObRawExprUtils::need_wrap_to_string(ObObjType param_type, ObObjType calc_typ case ObIntervalYMType: case ObNVarchar2Type: case ObNCharType: { - need_wrap = true; + // use the generic cast expr to process the enumset cast. + need_wrap = !src_res_type.is_enum_set_with_subschema(); break; } default : { @@ -7333,6 +7364,48 @@ int ObRawExprUtils::need_wrap_to_string(ObObjType param_type, ObObjType calc_typ return ret; } +int ObRawExprUtils::extract_enum_set_collation(const ObExprResType &src_res_type, + const sql::ObSQLSessionInfo *session, + ObObjMeta &obj_meta) +{ + int ret = OB_SUCCESS; + obj_meta = src_res_type.get_obj_meta(); + const ObEnumSetMeta *meta = NULL; + if (OB_FAIL(extract_enum_set_meta(src_res_type, session, meta))) { + LOG_WARN("fail to extrac enum set meta", K(ret)); + } else if (OB_NOT_NULL(meta)) { + obj_meta = meta->get_obj_meta(); + } + return ret; +} + +int ObRawExprUtils::extract_enum_set_meta(const ObExprResType &src_res_type, + const sql::ObSQLSessionInfo *session, + const ObEnumSetMeta *&meta) +{ + int ret = OB_SUCCESS; + meta = NULL; + if (src_res_type.is_enum_set_with_subschema()) { + if (OB_ISNULL(session) || OB_ISNULL(session->get_cur_exec_ctx())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session is null", K(ret), KP(session), KP(session->get_cur_exec_ctx())); + } else { + const ObEnumSetMeta *enum_set_meta = NULL; + const uint16_t subschema_id = src_res_type.get_subschema_id(); + if (OB_FAIL(session->get_cur_exec_ctx()->get_enumset_meta_by_subschema_id(subschema_id, + enum_set_meta))) { + LOG_WARN("fail to get enum set meta", K(ret), K(subschema_id)); + } else if (OB_ISNULL(enum_set_meta)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get meta", K(ret), K(subschema_id)); + } else { + meta = enum_set_meta; + } + } + } + return ret; +} + int ObRawExprUtils::extract_param_idxs(const ObRawExpr *expr, ObIArray ¶m_idxs) { int ret = OB_SUCCESS; @@ -8299,7 +8372,10 @@ int ObRawExprUtils::check_need_cast_expr(const ObExprResType &src_type, ignore_dup_cast_error = true; // scale adjust cast need ignore duplicate cast error. } } else if (ob_is_enumset_tc(out_type)) { - //no need add cast, will add column_conv later + // no need add cast, will add column_conv later + // currently, only the column convert expr's dst type will be enum/set. there is enough meta + // information in column_conv to do type conversion, so we keep no cast in both the old and + // new behaviors here. need_cast = false; } else if ((ob_is_xml_sql_type(in_type, src_type.get_subschema_id()) || ob_is_xml_pl_type(in_type, src_type.get_udt_id())) && ob_is_blob(out_type, out_cs_type)) { @@ -8307,7 +8383,7 @@ int ObRawExprUtils::check_need_cast_expr(const ObExprResType &src_type, // there are cases cannot skip cast expr, and xmltype cast to clob is not support and cast func will check: // case: select xmlserialize(content xmltype_var as clob) || xmltype_var from t; need_cast = false; - } else if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(in_type, out_type, + } else if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(src_type, out_type, is_same_need, need_wrap))) { LOG_WARN("failed to check_need_wrap_to_string", K(ret)); } else if (need_wrap) { @@ -9977,5 +10053,31 @@ int ObRawExprUtils::copy_and_formalize(const ObIArray &exprs, return ret; } +int ObRawExprUtils::need_extra_cast_for_enumset(const ObExprResType &src_type, + const ObExprResType &dst_type, + const ObSQLSessionInfo *session_info, + ObExprResType &extra_type, + bool &need_extra_cast) +{ + int ret = OB_SUCCESS; + need_extra_cast = false; + if (OB_ISNULL(session_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session is null", K(ret)); + } else if (src_type.is_enum_set_with_subschema() && + dst_type.is_string_or_lob_locator_type()) { + ObObjMeta param_obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(src_type, session_info, param_obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else if (param_obj_meta.get_collation_type() != dst_type.get_collation_type()) { + need_extra_cast = true; + extra_type = dst_type; + extra_type.set_collation(param_obj_meta); + extra_type.set_length(src_type.get_length()); + } + } + 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 9bf7e92ce..a2375c688 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.h +++ b/src/sql/resolver/expr/ob_raw_expr_util.h @@ -888,8 +888,14 @@ public: //extract from const value static int extract_int_value(const ObRawExpr *expr, int64_t &val); //used for enum set type - static int need_wrap_to_string(common::ObObjType param_type, common::ObObjType calc_type, + static int need_wrap_to_string(const ObExprResType &src_res_type, common::ObObjType calc_type, const bool is_same_type_need, bool &need_wrap); + static int extract_enum_set_collation(const ObExprResType &src_res_type, + const sql::ObSQLSessionInfo *session, + ObObjMeta &obj_meta); + static int extract_enum_set_meta(const ObExprResType &src_res_type, + const sql::ObSQLSessionInfo *session, + const ObEnumSetMeta *&meta); static bool contain_id(const common::ObIArray &ids, const uint64_t target); static int clear_exprs_flag(const common::ObIArray &exprs, ObExprInfoFlag flag); @@ -1283,6 +1289,12 @@ public: ObIArray &new_exprs, ObRawExprCopier *copier, ObSQLSessionInfo *session_info); +private: + static int need_extra_cast_for_enumset(const ObExprResType &src_type, + const ObExprResType &dst_type, + const ObSQLSessionInfo *session_info, + ObExprResType &extra_type, + bool &need_extra_cast); private : static int create_real_cast_expr(ObRawExprFactory &expr_factory, 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 ec5d13cc6..af2a0ff30 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 @@ -32,7 +32,9 @@ int ObRawExprWrapEnumSet::wrap_enum_set(ObDMLStmt &stmt) int ret = OB_SUCCESS; cur_stmt_ = &stmt; if (stmt.is_select_stmt()) { - //handle the target list of first level + // handle the target list of first level + // In the enum/set type with subschema, we keep this behavior now, as the obj meta information + // of the original expr is not valid that can be directly returned to the client. ObSelectStmt &select_stmt = static_cast(stmt); if (OB_FAIL(wrap_target_list(select_stmt))) { LOG_WARN("failed to wrap target list", K(ret)); @@ -83,12 +85,49 @@ int ObRawExprWrapEnumSet::wrap_sub_select(ObInsertStmt &stmt) } else if (OB_FAIL(static_cast(conv_expr->get_param_expr(0)) ->get_value().get_int32(const_value))) { LOG_WARN("failed to get obj type from convert expr", K(ret)); + } else if (conv_expr->get_param_expr(4)->is_enum_set_with_subschema()) { + ObRawExpr *arg_expr = conv_expr->get_param_expr(4); + if (arg_expr->get_data_type() == const_value) { + bool need_to_str = true; + // same type + if (OB_ISNULL(my_session_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session is null", K(ret)); + } else if (my_session_->get_ddl_info().is_ddl()) { + uint16_t subschema_id = 0; + ObExecContext *exec_ctx = NULL; + if (conv_expr->is_enum_set_with_subschema()) { + need_to_str = (arg_expr->get_subschema_id() != conv_expr->get_subschema_id()); + } else if (OB_ISNULL(exec_ctx = my_session_->get_cur_exec_ctx())) { + } else if (OB_UNLIKELY(conv_expr->get_enum_set_values().empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("str values for enum set expr is empty", K(ret)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_type_info( + conv_expr->get_result_type().get_obj_meta(), + conv_expr->get_enum_set_values(), + subschema_id))) { + LOG_WARN("failed to get subschema id by udt id", K(ret)); + } else if (subschema_id == arg_expr->get_subschema_id()) { + need_to_str = false; + } + } + if (OB_FAIL(ret) || !need_to_str) { + } else if (OB_FAIL(ObRawExprUtils::create_type_to_str_expr(expr_factory_, + arg_expr, + wrapped_expr, + my_session_, + true /*is_type_to_str*/, + static_cast(const_value)))) { + LOG_WARN("failed to create_type_to_string_expr", K(ret)); + } + } } else if (OB_FAIL(wrap_type_to_str_if_necessary(conv_expr->get_param_expr(4), static_cast(const_value), is_same_need, wrapped_expr))) { LOG_WARN("failed to wrap_type_to_str_if_necessary", K(i), K(ret)); - } else if (NULL != wrapped_expr) { + } + if (OB_SUCC(ret) && NULL != wrapped_expr) { conv_expr->get_param_expr(4) = wrapped_expr; } } @@ -126,12 +165,28 @@ int ObRawExprWrapEnumSet::wrap_value_vector(ObInsertStmt &stmt) } else { int64_t index = i % desc_count; ObSysFunRawExpr *new_expr = NULL; - if (OB_FAIL(wrap_type_to_str_if_necessary(value_expr, stmt.get_values_desc().at(index)->get_data_type(), + const ObExprResType &dst_type = stmt.get_values_desc().at(index)->get_result_type(); + if (value_expr->is_enum_set_with_subschema()) { + if (!ob_is_enum_or_set_type(dst_type.get_type())) { + // skip wrap to string, it can cast directly + } else if (dst_type.is_enum_set_with_subschema() && + dst_type.get_subschema_id() == value_expr->get_subschema_id()) { + // same type, no need to cast + } else if (OB_FAIL(ObRawExprUtils::create_type_to_str_expr(expr_factory_, + value_expr, + new_expr, + my_session_, + true /*is_type_to_str*/, + dst_type.get_type()))) { + LOG_WARN("failed to create_type_to_string_expr", K(ret)); + } + } else if (OB_FAIL(wrap_type_to_str_if_necessary(value_expr, dst_type.get_type(), is_same_need, new_expr))) { LOG_WARN("failed to wrap_type_to_str_if_necessary", K(i), K(ret)); - } else if (NULL != new_expr) { + } + if (OB_SUCC(ret) && NULL != new_expr) { value_expr = new_expr; - } else {/*do nothing*/} + } } } } @@ -150,9 +205,15 @@ int ObRawExprWrapEnumSet::wrap_target_list(ObSelectStmt &select_stmt) LOG_WARN("expr of select_items should not be NULL", K(i), K(ret)); } else if (ob_is_enumset_tc(target_expr->get_data_type())) { ObSysFunRawExpr *new_expr = NULL; + // the return type of mysql client for enum/set is FIELD_TYPE_STRING instead of + // FIELD_TYPE_VAR_STRING. + const ObObjType dst_type = target_expr->is_enum_set_with_subschema() ? + ObCharType : ObVarcharType; if (OB_FAIL(ObRawExprUtils::create_type_to_str_expr(expr_factory_, target_expr, new_expr, - my_session_, is_type_to_str))) { + my_session_, + is_type_to_str, + dst_type))) { LOG_WARN("failed to create_type_to_string_expr", K(i), K(target_expr), K(ret)); } else if (OB_ISNULL(new_expr)) { ret = OB_ERR_UNEXPECTED; @@ -275,7 +336,7 @@ int ObRawExprWrapEnumSet::visit(ObColumnRefRawExpr &expr) int ObRawExprWrapEnumSet::visit(ObWinFunRawExpr &expr) { int ret = OB_SUCCESS; - if (expr.has_enum_set_column() || expr.has_flag(CNT_SUB_QUERY)) { + if (has_enumset_expr_need_wrap(expr) || expr.has_flag(CNT_SUB_QUERY)) { if (T_WIN_FUN_LEAD == expr.get_func_type() || T_WIN_FUN_LAG == expr.get_func_type()) { ObIArray &real_parm_exprs = expr.get_func_params(); @@ -303,7 +364,7 @@ int ObRawExprWrapEnumSet::visit(ObOpRawExpr &expr) { int ret = OB_SUCCESS; ObExprOperator *op = NULL; - if (!expr.has_enum_set_column() && !expr.has_flag(CNT_SUB_QUERY)) { + if (!has_enumset_expr_need_wrap(expr) && !expr.has_flag(CNT_SUB_QUERY)) { //不含有enum或者set,则不需要做任何转换 } else if (T_OP_ROW != expr.get_expr_type()) { if (OB_ISNULL(op = expr.get_op())) { @@ -322,10 +383,10 @@ int ObRawExprWrapEnumSet::visit(ObOpRawExpr &expr) } else if (OB_ISNULL(left_expr = expr.get_param_expr(0)) || OB_ISNULL(right_expr = expr.get_param_expr(1))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child expr is NULL", K(left_expr), K(right_expr), K(ret)); - } else if ((left_expr->has_enum_set_column() || left_expr->has_flag(CNT_SUB_QUERY)) && + } else if ((has_enumset_expr_need_wrap(*left_expr) || left_expr->has_flag(CNT_SUB_QUERY)) && OB_FAIL(visit_left_expr(expr, row_dimension, cmp_types))) { LOG_WARN("failed to visit left expr", K(expr), K(ret)); - } else if ((right_expr->has_enum_set_column() || right_expr->has_flag(CNT_SUB_QUERY)) + } else if ((has_enumset_expr_need_wrap(*right_expr) || right_expr->has_flag(CNT_SUB_QUERY)) && OB_FAIL(visit_right_expr(*right_expr, row_dimension, cmp_types, expr.get_expr_type()))) { LOG_WARN("failed to visit right expr", K(expr), K(ret)); @@ -452,7 +513,7 @@ int ObRawExprWrapEnumSet::check_and_wrap_left(ObRawExpr &expr, int64_t idx, for (int64_t i = 0; OB_SUCC(ret) && i < target_num && !(need_numberic && need_varchar); ++i) { bool need_wrap = false; dest_type = cmp_types.at(row_dimension * i + idx).get_type(); - if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(expr_type, + if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(expr.get_result_type(), dest_type, is_same_type_need, need_wrap))) { LOG_WARN("failed to check whether need wrap", K(i), K(expr), K(ret)); @@ -647,7 +708,7 @@ int ObRawExprWrapEnumSet::wrap_type_to_str_if_necessary(ObRawExpr *expr, if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(expr->get_data_type(), dest_type, + } else if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(expr->get_result_type(), dest_type, is_same_need, need_wrap))) { LOG_WARN("failed to check_need_wrap_to_string", K(ret)); } else if (need_wrap && OB_FAIL(ObRawExprUtils::create_type_to_str_expr(expr_factory_, expr, @@ -692,7 +753,7 @@ int ObRawExprWrapEnumSet::visit(ObCaseOpRawExpr &expr) LOG_WARN("failed to wrap_type_to_str_if_necessary", K(i), K(ret)); } else if (NULL != wrapped_expr && OB_FAIL(expr.replace_when_param_expr(i, wrapped_expr))){ LOG_WARN("failed to replace_when_param_expr", K(i), K(ret)); - } else if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(arg_type, calc_type, is_same_need, need_wrap))) { + } else if (OB_FAIL(ObRawExprUtils::need_wrap_to_string(arg_param_expr->get_result_type(), calc_type, is_same_need, need_wrap))) { LOG_WARN("failed to check whether need wrap", K(arg_type), K(calc_type), K(ret)); } else if (need_wrap) { need_varchar = true; @@ -758,7 +819,7 @@ int ObRawExprWrapEnumSet::visit(ObCaseOpRawExpr &expr) int ObRawExprWrapEnumSet::visit(ObAggFunRawExpr &expr) { int ret = OB_SUCCESS; - if ((expr.has_enum_set_column() || expr.has_flag(CNT_SUB_QUERY)) && + if ((has_enumset_expr_need_wrap(expr) || expr.has_flag(CNT_SUB_QUERY)) && (T_FUN_GROUP_CONCAT == expr.get_expr_type() || T_FUN_MAX == expr.get_expr_type() || T_FUN_MIN == expr.get_expr_type() || @@ -857,7 +918,7 @@ int ObRawExprWrapEnumSet::visit(ObAliasRefRawExpr &expr) if (OB_ISNULL(ref_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ref expr is null", K(ret)); - } else if (expr.has_enum_set_column() && OB_FAIL(analyze_expr(ref_expr))) { + } else if (has_enumset_expr_need_wrap(expr) && OB_FAIL(analyze_expr(ref_expr))) { LOG_WARN("failed to analyze expr", K(ret)); } else {/*do nothing*/} return ret; @@ -925,7 +986,7 @@ int ObRawExprWrapEnumSet::visit_query_ref_expr(ObQueryRefRawExpr &expr, const bool is_same_need) { int ret = OB_SUCCESS; - if (!expr.has_enum_set_column() && !expr.has_flag(CNT_SUB_QUERY)) { + if (!has_enumset_expr_need_wrap(expr) && !expr.has_flag(CNT_SUB_QUERY)) { // no-op if expr doesn't have enumset column } else if (1 == expr.get_output_column() && expr.is_set() && ob_is_enumset_tc(expr.get_column_types().at(0).get_type())) { @@ -979,5 +1040,23 @@ int ObRawExprWrapEnumSet::wrap_param_expr(ObIArray ¶m_exprs, ObO return ret; } +bool ObRawExprWrapEnumSet::has_enumset_expr_need_wrap(const ObRawExpr &expr) +{ + int need_wrap = false; + if (expr.has_enum_set_column()) { + if (expr.get_result_type().is_enum_or_set()) { + need_wrap = !expr.is_enum_set_with_subschema(); + } + for (int64_t i = 0; !need_wrap && i < expr.get_param_count(); ++i) { + const ObRawExpr *param_expr = expr.get_param_expr(i); + if (OB_ISNULL(param_expr)) { + } else { + need_wrap = has_enumset_expr_need_wrap(*param_expr); + } + } + } + return need_wrap; +} + } // namespace sql } // namespace oceanbase 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 25deb7a63..ccdb2d777 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 @@ -76,6 +76,7 @@ private: const common::ObObjType dest_type, const bool is_same_need); int wrap_param_expr(ObIArray ¶m_exprs, ObObjType dest_typ); + static bool has_enumset_expr_need_wrap(const ObRawExpr &expr); private: ObDMLStmt *cur_stmt_; ObRawExprFactory &expr_factory_; diff --git a/src/sql/resolver/mv/ob_mv_provider.cpp b/src/sql/resolver/mv/ob_mv_provider.cpp index 7bd7ed6e9..7fa98b9d8 100644 --- a/src/sql/resolver/mv/ob_mv_provider.cpp +++ b/src/sql/resolver/mv/ob_mv_provider.cpp @@ -107,7 +107,7 @@ int ObMVProvider::init_mv_provider(const share::SCN &last_refresh_scn, LOG_WARN("failed to collect dep infos", K(ret)); } else if (OB_FAIL(dependency_infos_.assign(dependency_infos))) { LOG_WARN("failed to assign fixed array", K(ret)); - } else if (OB_FAIL(check_mv_column_type(mv_schema, view_stmt))) { + } else if (OB_FAIL(check_mv_column_type(mv_schema, view_stmt, *session_info))) { if (OB_ERR_MVIEW_CAN_NOT_FAST_REFRESH == ret) { inited_ = true; refreshable_type_ = OB_MV_REFRESH_INVALID; @@ -215,7 +215,8 @@ int ObMVProvider::get_mv_dependency_infos(ObIArray &dep_infos) // if the result type from mv_schema and view_stmt is different, no refresh method is allowed // get new column info same as ObCreateViewResolver::add_column_infos int ObMVProvider::check_mv_column_type(const ObTableSchema *mv_schema, - const ObSelectStmt *view_stmt) + const ObSelectStmt *view_stmt, + ObSQLSessionInfo &session) { int ret = OB_SUCCESS; if (OB_ISNULL(mv_schema) || OB_ISNULL(view_stmt)) { @@ -236,6 +237,7 @@ int ObMVProvider::check_mv_column_type(const ObTableSchema *mv_schema, } else if (OB_FAIL(ObCreateViewResolver::fill_column_meta_infos(*select_items.at(i).expr_, mv_schema->get_charset_type(), mv_schema->get_table_id(), + session, cur_column))) { LOG_WARN("failed to fill column meta infos", K(ret), K(cur_column)); } else if (OB_FAIL(check_mv_column_type(*org_column, cur_column))) { diff --git a/src/sql/resolver/mv/ob_mv_provider.h b/src/sql/resolver/mv/ob_mv_provider.h index 97f198f60..8accacb5c 100644 --- a/src/sql/resolver/mv/ob_mv_provider.h +++ b/src/sql/resolver/mv/ob_mv_provider.h @@ -65,7 +65,8 @@ public: const bool gen_error, bool &is_vars_matched); private: - int check_mv_column_type(const ObTableSchema *mv_schema, const ObSelectStmt *view_stmt); + int check_mv_column_type(const ObTableSchema *mv_schema, const ObSelectStmt *view_stmt, + ObSQLSessionInfo &session); int check_mv_column_type(const ObColumnSchemaV2 &org_column, const ObColumnSchemaV2 &cur_column); int check_column_type_and_accuracy(const ObColumnSchemaV2 &org_column, const ObColumnSchemaV2 &cur_column, diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index 67eecacf6..547cb9edf 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -517,7 +517,10 @@ int ObTransformPreProcess::add_all_rowkey_columns_to_stmt(const ObTableSchema &t } else if (OB_FAIL(column_items.push_back(column_item))) { LOG_WARN("failed to push back column item", K(ret)); } else if (FALSE_IT(rowkey->clear_explicited_referece())) { - } else if (OB_FAIL(rowkey->formalize(NULL))) { + } else if (OB_ISNULL(ctx_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("trans ctx is null", K(ret)); + } else if (OB_FAIL(rowkey->formalize(ctx_->session_info_))) { LOG_WARN("formalize rowkey failed", K(ret)); } else if (OB_FAIL(rowkey->pull_relation_id())) { LOG_WARN("failed to pullup relation ids", K(ret)); @@ -5825,17 +5828,28 @@ int ObTransformPreProcess::transform_in_or_notin_expr_without_row(ObRawExprFacto ObRawExpr *right_expr = in_expr->get_param_expr(1); ObSEArray distinct_types; for (int i = 0; OB_SUCC(ret) && i < right_expr->get_param_count(); i++) { - if (OB_ISNULL(right_expr->get_param_expr(i))) { + ObRawExpr *param_expr = right_expr->get_param_expr(i); + if (OB_ISNULL(param_expr)) { ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid null param expr", K(ret), K(right_expr->get_param_expr(i))); + LOG_WARN("invalid null param expr", K(ret), K(param_expr)); } else { - ObObjType obj_type = right_expr->get_param_expr(i)->get_result_type().get_type(); - ObCollationType coll_type = right_expr->get_param_expr(i) - ->get_result_type().get_collation_type(); - ObCollationLevel coll_level = right_expr->get_param_expr(i) - ->get_result_type().get_collation_level(); - ObScale scale = right_expr->get_param_expr(i)->get_result_type().get_scale(); - if (OB_UNLIKELY(obj_type == ObMaxType)) { + ObObjType obj_type = param_expr->get_result_type().get_type(); + ObCollationType coll_type = param_expr->get_result_type().get_collation_type(); + ObCollationLevel coll_level = param_expr->get_result_type().get_collation_level(); + ObScale scale = param_expr->get_result_type().get_scale(); + if (param_expr->is_enum_set_with_subschema()) { + ObObjMeta obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(param_expr->get_result_type(), + &session, + obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + coll_type = obj_meta.get_collation_type(); + coll_level = obj_meta.get_collation_level(); + } + } + if (OB_FAIL(ret)) { + } else if (OB_UNLIKELY(obj_type == ObMaxType)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected obj type", K(ret), K(obj_type), K(*in_expr)); } else if (OB_FAIL(add_var_to_array_no_dup(distinct_types, @@ -5867,14 +5881,25 @@ int ObTransformPreProcess::transform_in_or_notin_expr_without_row(ObRawExprFacto same_type_exprs.reuse(); DistinctObjMeta obj_meta = distinct_types.at(i); for (int j = 0; OB_SUCC(ret) && j < right_expr->get_param_count(); j++) { - ObObjType obj_type = right_expr->get_param_expr(j)->get_result_type().get_type(); - ObCollationType coll_type = right_expr->get_param_expr(j) - ->get_result_type().get_collation_type(); - ObCollationLevel coll_level = right_expr->get_param_expr(j) - ->get_result_type().get_collation_level(); - ObScale scale = right_expr->get_param_expr(j)->get_result_type().get_scale(); - DistinctObjMeta tmp_meta(obj_type, coll_type, coll_level, scale); - if (obj_meta == tmp_meta + ObRawExpr *param_expr = right_expr->get_param_expr(j); + ObObjType obj_type = param_expr->get_result_type().get_type(); + ObCollationType coll_type = param_expr->get_result_type().get_collation_type(); + ObCollationLevel coll_level = param_expr->get_result_type().get_collation_level(); + ObScale scale = param_expr->get_result_type().get_scale(); + if (param_expr->is_enum_set_with_subschema()) { + ObObjMeta enum_set_obj_meta; + if (OB_FAIL(ObRawExprUtils::extract_enum_set_collation(param_expr->get_result_type(), + &session, + enum_set_obj_meta))) { + LOG_WARN("fail to extract enum set cs type", K(ret)); + } else { + coll_type = enum_set_obj_meta.get_collation_type(); + coll_level = enum_set_obj_meta.get_collation_level(); + } + } + DistinctObjMeta tmp_meta(obj_type, coll_type, coll_level, scale); + if (OB_FAIL(ret)) { + } else if (obj_meta == tmp_meta && OB_FAIL(same_type_exprs.push_back(right_expr->get_param_expr(j)))) { LOG_WARN("failed to add param expr", K(ret)); } else { /* do nothing */ } diff --git a/src/sql/rewrite/ob_transform_pre_process.h b/src/sql/rewrite/ob_transform_pre_process.h index bbe38481e..cb6bb99b3 100644 --- a/src/sql/rewrite/ob_transform_pre_process.h +++ b/src/sql/rewrite/ob_transform_pre_process.h @@ -39,7 +39,7 @@ struct DistinctObjMeta : obj_type_(obj_type), coll_type_(coll_type), coll_level_(coll_level), scale_(scale) { - if (!ObDatumFuncs::is_string_type(obj_type_)) { + if (!ObDatumFuncs::is_string_type(obj_type_) && !ob_is_enum_or_set_type(obj_type_)) { coll_type_ = CS_TYPE_MAX; coll_level_ = CS_LEVEL_INVALID; } diff --git a/src/sql/rewrite/ob_transform_rule.cpp b/src/sql/rewrite/ob_transform_rule.cpp index 1f92f11be..1ce7c73f9 100644 --- a/src/sql/rewrite/ob_transform_rule.cpp +++ b/src/sql/rewrite/ob_transform_rule.cpp @@ -28,6 +28,7 @@ #include "lib/json/ob_json_print_utils.h" #include "sql/optimizer/ob_optimizer_util.h" #include "sql/printer/ob_select_stmt_printer.h" +#include "sql/executor/ob_memory_tracker.h" namespace oceanbase { namespace sql @@ -306,11 +307,14 @@ int ObTransformRule::accept_transform(common::ObIArray &parent_ ObDMLStmt *top_stmt = parent_stmts.empty() ? stmt : parent_stmts.at(0).stmt_; bool is_expected = false; bool is_original_expected = false; + const int64_t check_try_times = 32; ObDMLStmt *tmp1 = NULL; ObDMLStmt *tmp2 = NULL; cost_based_trans_tried_ = true; BEGIN_OPT_TRACE_EVA_COST; - if (OB_ISNULL(ctx_) || OB_ISNULL(stmt) || OB_ISNULL(trans_stmt) || OB_ISNULL(top_stmt)) { + if (OB_UNLIKELY((OB_SUCCESS != (ret = TRY_CHECK_MEM_STATUS(check_try_times))))) { + LOG_WARN("Exceeded memory usage limit", K(ret)); + } else if (OB_ISNULL(ctx_) || OB_ISNULL(stmt) || OB_ISNULL(trans_stmt) || OB_ISNULL(top_stmt)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("context is null", K(ret), K(ctx_), K(stmt), K(trans_stmt), K(top_stmt)); } else if (force_accept) { diff --git a/src/sql/rewrite/ob_transformer_impl.cpp b/src/sql/rewrite/ob_transformer_impl.cpp index f12345707..277d9c649 100644 --- a/src/sql/rewrite/ob_transformer_impl.cpp +++ b/src/sql/rewrite/ob_transformer_impl.cpp @@ -1015,7 +1015,10 @@ int ObTransformerImpl::add_all_rowkey_columns_to_stmt(const ObTableSchema &table } else if (OB_FAIL(column_items.push_back(column_item))) { LOG_WARN("failed to push back column item", K(ret)); } else if (FALSE_IT(rowkey->clear_explicited_referece())) { - } else if (OB_FAIL(rowkey->formalize(NULL))) { + } else if (OB_ISNULL(ctx_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("trans ctx is null", K(ret)); + } else if (OB_FAIL(rowkey->formalize(ctx_->session_info_))) { LOG_WARN("formalize rowkey failed", K(ret)); } else if (OB_FAIL(rowkey->pull_relation_id())) { LOG_WARN("failed to pullup relation ids", K(ret)); diff --git a/src/sql/session/ob_sql_session_info.cpp b/src/sql/session/ob_sql_session_info.cpp index 5fe0601df..f2824c7cd 100644 --- a/src/sql/session/ob_sql_session_info.cpp +++ b/src/sql/session/ob_sql_session_info.cpp @@ -3017,6 +3017,7 @@ void ObSQLSessionInfo::ObCachedTenantConfigInfo::refresh() enable_decimal_int_type_ = tenant_config->_enable_decimal_int_type; sql_plan_management_mode_ = ObSqlPlanManagementModeChecker::get_spm_mode_by_string( tenant_config->sql_plan_management_mode.get_value_string()); + enable_enum_set_subschema_ = tenant_config->_enable_enum_set_subschema; // 7. print_sample_ppm_ for flt ATOMIC_STORE(&print_sample_ppm_, tenant_config->_print_sample_ppm); // 8. _enable_enhanced_cursor_validation diff --git a/src/sql/session/ob_sql_session_info.h b/src/sql/session/ob_sql_session_info.h index 5cc490c7f..23f71f36e 100644 --- a/src/sql/session/ob_sql_session_info.h +++ b/src/sql/session/ob_sql_session_info.h @@ -727,6 +727,7 @@ public: last_check_ec_ts_(0), sql_plan_management_mode_(0), enable_enhanced_cursor_validation_(false), + enable_enum_set_subschema_(false), session_(session) { } @@ -753,6 +754,7 @@ public: bool get_enable_decimal_int_type() const { return enable_decimal_int_type_; } int64_t get_sql_plan_management_mode() const { return sql_plan_management_mode_; } bool enable_enhanced_cursor_validation() const { return enable_enhanced_cursor_validation_; } + bool enable_enum_set_subschema() const { return enable_enum_set_subschema_; } private: //租户级别配置项缓存session 上,避免每次获取都需要刷新 bool is_external_consistent_; @@ -779,6 +781,7 @@ public: int64_t last_check_ec_ts_; int64_t sql_plan_management_mode_; bool enable_enhanced_cursor_validation_; + bool enable_enum_set_subschema_; ObSQLSessionInfo *session_; }; @@ -1446,6 +1449,11 @@ public: cached_tenant_config_info_.refresh(); return cached_tenant_config_info_.enable_enhanced_cursor_validation(); } + bool is_enable_enum_set_with_subschema() + { + cached_tenant_config_info_.refresh(); + return cached_tenant_config_info_.enable_enum_set_subschema(); + } int get_tmp_table_size(uint64_t &size); int ps_use_stream_result_set(bool &use_stream); void set_proxy_version(uint64_t v) { proxy_version_ = v; } diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result index 1d8d6e292..c2ba22908 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result @@ -212,6 +212,7 @@ plsql_debug plsql_v2_compatibility px_task_size px_workers_per_cpu_quota +query_memory_limit_percentage query_response_time_flush query_response_time_range_base query_response_time_stats @@ -336,6 +337,7 @@ _enable_decimal_int_type _enable_defensive_check _enable_easy_keepalive _enable_enhanced_cursor_validation +_enable_enum_set_subschema _enable_hash_join_hasher _enable_hash_join_processor _enable_hgby_llc_ndv_adaptive diff --git a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_from_unixtime.result b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_from_unixtime.result index bbb2e9e51..f3144c560 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_from_unixtime.result +++ b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_from_unixtime.result @@ -1317,7 +1317,7 @@ Query Plan =============================================== Outputs & filters: ------------------------------------- - 0 - output([from_unixtime(cast(1234567890, DECIMAL(10, 0)), enum_to_str('', t.t28))]), filter(nil), rowset=16 + 0 - output([from_unixtime(cast(1234567890, DECIMAL(10, 0)), cast(t.t28, VARCHAR(1048576)))]), filter(nil), rowset=16 access([t.t28]), partitions(p0) is_index_back=false, is_global_index=false, range_key([t.__pk_increment]), range(MIN ; MAX)always true @@ -1358,7 +1358,7 @@ Query Plan =============================================== Outputs & filters: ------------------------------------- - 0 - output([from_unixtime(cast(1234567890, DECIMAL(10, 0)), set_to_str('', t.t29))]), filter(nil), rowset=16 + 0 - output([from_unixtime(cast(1234567890, DECIMAL(10, 0)), cast(t.t29, VARCHAR(1048576)))]), filter(nil), rowset=16 access([t.t29]), partitions(p0) is_index_back=false, is_global_index=false, range_key([t.__pk_increment]), range(MIN ; MAX)always true diff --git a/unittest/sql/resolver/test_resolver.cpp b/unittest/sql/resolver/test_resolver.cpp index f2fb98213..38f8f9c9f 100644 --- a/unittest/sql/resolver/test_resolver.cpp +++ b/unittest/sql/resolver/test_resolver.cpp @@ -340,7 +340,8 @@ void TestResolver::do_join_order_test() table_id, *idx_schema, index_keys, - ordering); + ordering, + &session_info_); ASSERT_EQ(ret, OB_SUCCESS); std::string idx_name_with_column; get_index_name(idx_name_with_column, *idx_schema);