/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX SQL_PC #include "ob_prepare_stmt_struct.h" #include "lib/utility/ob_print_utils.h" #include "sql/plan_cache/ob_ps_sql_utils.h" #include "sql/plan_cache/ob_ps_cache.h" namespace oceanbase { using namespace common; namespace sql { int ObPsSqlKey::deep_copy(const ObPsSqlKey& other) { int ret = OB_SUCCESS; if (OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("allocator is invalid", K(ret)); } else { db_id_ = other.db_id_; if (OB_FAIL(ObPsSqlUtils::deep_copy_str(*allocator_, other.get_ps_sql(), ps_sql_))) { LOG_WARN("deep copy str failed", K(other), K(ret)); } } return ret; } ObPsSqlKey& ObPsSqlKey::operator=(const ObPsSqlKey& other) { if (this != &other) { db_id_ = other.db_id_; ps_sql_ = other.ps_sql_; } return *this; } bool ObPsSqlKey::operator==(const ObPsSqlKey& other) const { return db_id_ == other.db_id_ && ps_sql_.compare(other.get_ps_sql()) == 0; } int64_t ObPsSqlKey::hash() const { int64_t hash_val = 0; hash_val = murmurhash(&db_id_, sizeof(uint64_t), hash_val); hash_val = ps_sql_.hash(hash_val); return hash_val; } ObPsStmtItem::ObPsStmtItem() : ref_count_(1), db_id_(OB_INVALID_ID), ps_sql_(), stmt_id_(OB_INVALID_STMT_ID), is_expired_evicted_(false), allocator_(NULL), external_allocator_(NULL) {} ObPsStmtItem::ObPsStmtItem(const ObPsStmtId ps_stmt_id) : ref_count_(1), db_id_(OB_INVALID_ID), ps_sql_(), stmt_id_(ps_stmt_id), is_expired_evicted_(false), allocator_(NULL), external_allocator_(NULL) {} ObPsStmtItem::ObPsStmtItem(ObIAllocator* inner_allocator, ObIAllocator* external_allocator) : ref_count_(1), db_id_(OB_INVALID_ID), ps_sql_(), stmt_id_(OB_INVALID_STMT_ID), is_expired_evicted_(false), allocator_(inner_allocator), external_allocator_(external_allocator) {} int ObPsStmtItem::deep_copy(const ObPsStmtItem& other) { int ret = OB_SUCCESS; if (OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("allocator is invalid", K(ret)); } else { stmt_id_ = other.stmt_id_; db_id_ = other.db_id_; // not copy refcount if (OB_FAIL(ObPsSqlUtils::deep_copy_str(*allocator_, other.get_ps_sql(), ps_sql_))) { LOG_WARN("deep copy str failed", K(other), K(ret)); } } return ret; } ObPsStmtItem& ObPsStmtItem::operator=(const ObPsStmtItem& other) { if (this != &other) { ref_count_ = other.ref_count_; db_id_ = other.get_db_id(); ps_sql_ = other.get_ps_sql(); stmt_id_ = other.get_ps_stmt_id(); is_expired_evicted_ = other.is_expired_evicted_; } return *this; } bool ObPsStmtItem::is_valid() const { bool bret = false; if (!ps_sql_.empty() && OB_INVALID_STMT_ID != stmt_id_) { bret = true; } return bret; } int ObPsStmtItem::get_convert_size(int64_t& cv_size) const { cv_size = sizeof(ObPsStmtItem); cv_size += ps_sql_.length() + 1; return OB_SUCCESS; } bool ObPsStmtItem::check_erase_inc_ref_count() { bool need_erase = false; bool cas_ret = false; do { need_erase = false; int64_t cur_ref_cnt = ATOMIC_LOAD(&ref_count_); int64_t next_ref_cnt = cur_ref_cnt + 1; if (0 == cur_ref_cnt) { need_erase = true; break; } cas_ret = ATOMIC_BCAS(&ref_count_, cur_ref_cnt, next_ref_cnt); LOG_TRACE("ps item check erase inc ref count after cas", K(cur_ref_cnt), K(next_ref_cnt), K(cas_ret)); } while (!cas_ret); LOG_TRACE("ps item inc ref count", K(*this), K(need_erase)); return need_erase; } void ObPsStmtItem::dec_ref_count_check_erase() { int ret = OB_SUCCESS; LOG_TRACE("ps item dec ref count", K(*this)); int64_t ref_count = ATOMIC_SAF(&ref_count_, 1); if (ref_count > 0) { LOG_TRACE("ps item dec ref count", K(ref_count)); } else if (0 == ref_count) { LOG_INFO("free ps item", K(ref_count), K(*this)); ObPsStmtItem* ps_item = this; ObIAllocator* allocator = NULL; if (OB_ISNULL(allocator = get_external_allocator())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(allocator), K(ret)); } else { ps_item->~ObPsStmtItem(); allocator->free(ps_item); } } else if (ref_count < 0) { BACKTRACE(ERROR, true, "ObPsStmtItem %p ref count < 0, ref_count = %ld", this, ref_count); } } int ObPsSqlMeta::add_param_field(const ObField& field) { int ret = OB_SUCCESS; ObField tmp_field; if (OB_FAIL(tmp_field.full_deep_copy(field, allocator_))) { LOG_WARN("deep copy field failed", K(ret)); } else if (OB_FAIL(param_fields_.push_back(tmp_field))) { LOG_WARN("push back field param failed", K(ret)); } else { LOG_DEBUG("succ to push back param field", K(field)); } return ret; } int ObPsSqlMeta::add_column_field(const ObField& field) { int ret = OB_SUCCESS; ObField tmp_field; if (OB_FAIL(tmp_field.full_deep_copy(field, allocator_))) { LOG_WARN("deep copy field failed", K(ret)); } else if (OB_FAIL(column_fields_.push_back(tmp_field))) { LOG_WARN("push back field param failed", K(ret)); } else { LOG_DEBUG("succ to push back column field", K(field)); } return ret; } int ObPsSqlMeta::reverse_fileds(int64_t param_size, int64_t column_size) { int64_t ret = OB_SUCCESS; if (OB_FAIL(param_fields_.init(param_size))) { LOG_WARN("fail to init param fields", K(ret), K(param_size)); } else if (OB_FAIL(column_fields_.init(column_size))) { LOG_WARN("fail to init column fields", K(ret), K(column_size)); } return ret; } int ObPsSqlMeta::deep_copy(const ObPsSqlMeta& sql_meta) { int ret = OB_SUCCESS; const int64_t column_size = sql_meta.get_column_size(); const int64_t param_size = sql_meta.get_param_size(); if (OB_FAIL(reverse_fileds(param_size, column_size))) { LOG_WARN("reserve_fix_size failed", K(column_size), K(param_size)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < param_size; ++i) { if (OB_FAIL(add_param_field(sql_meta.get_param_fields().at(i)))) { LOG_WARN("add column field failed", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < column_size; ++i) { if (OB_FAIL(add_column_field(sql_meta.get_column_fields().at(i)))) { LOG_WARN("add column field failed", K(ret)); } } } return ret; } int ObPsSqlMeta::get_convert_size(int64_t& cv_size) const { int ret = OB_SUCCESS; cv_size = 0; int64_t convert_size = sizeof(ObPsSqlMeta); for (int i = 0; OB_SUCC(ret) && i < column_fields_.count(); ++i) { convert_size += column_fields_.at(i).get_convert_size(); } for (int i = 0; OB_SUCC(ret) && i < param_fields_.count(); ++i) { convert_size += param_fields_.at(i).get_convert_size(); } if (OB_SUCC(ret)) { cv_size = convert_size; } return ret; } ObPsStmtInfo::ObPsStmtInfo(ObIAllocator* inner_allocator) : stmt_type_(stmt::T_NONE), ps_stmt_checksum_(0), db_id_(OB_INVALID_ID), ps_sql_(), ps_sql_meta_(inner_allocator), ref_count_(1), question_mark_count_(0), can_direct_use_param_(false), has_complex_argument_(false), item_and_info_size_(0), last_closed_timestamp_(0), dep_objs_(NULL), dep_objs_cnt_(0), ps_item_(NULL), is_expired_evicted_(false), allocator_(inner_allocator), external_allocator_(NULL), is_sensitive_sql_(false) {} ObPsStmtInfo::ObPsStmtInfo(ObIAllocator* inner_allocator, ObIAllocator* external_allocator) : stmt_type_(stmt::T_NONE), ps_stmt_checksum_(0), db_id_(OB_INVALID_ID), ps_sql_(), ps_sql_meta_(inner_allocator), ref_count_(1), question_mark_count_(0), can_direct_use_param_(false), has_complex_argument_(false), item_and_info_size_(0), last_closed_timestamp_(0), dep_objs_(NULL), dep_objs_cnt_(0), ps_item_(NULL), tenant_version_(OB_INVALID_VERSION), is_expired_(false), is_expired_evicted_(false), allocator_(inner_allocator), external_allocator_(external_allocator), is_sensitive_sql_(false) {} bool ObPsStmtInfo::is_valid() const { return !ps_sql_.empty(); } int ObPsStmtInfo::deep_copy(const ObPsStmtInfo& other) { int ret = OB_SUCCESS; if (OB_ISNULL(allocator_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("allocator is invalid", K(ret)); } else { stmt_type_ = other.stmt_type_; ps_stmt_checksum_ = other.ps_stmt_checksum_; db_id_ = other.db_id_; question_mark_count_ = other.question_mark_count_; is_sensitive_sql_ = other.is_sensitive_sql_; can_direct_use_param_ = other.can_direct_use_param(); has_complex_argument_ = other.has_complex_argument(); item_and_info_size_ = other.item_and_info_size_; ps_item_ = other.ps_item_; tenant_version_ = other.tenant_version_; is_expired_ = other.is_expired_; is_expired_evicted_ = other.is_expired_evicted_; if (other.get_dep_objs_cnt() > 0) { dep_objs_cnt_ = other.get_dep_objs_cnt(); if (NULL == (dep_objs_ = reinterpret_cast( allocator_->alloc(dep_objs_cnt_ * sizeof(ObSchemaObjVersion))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc memory", K(ret), K(dep_objs_cnt_)); } else { MEMCPY(dep_objs_, other.get_dep_objs(), dep_objs_cnt_ * sizeof(ObSchemaObjVersion)); } } if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(ObPsSqlUtils::deep_copy_str(*allocator_, other.get_ps_sql(), ps_sql_))) { LOG_WARN("deep copy str failed", K(other), K(ret)); } else if (OB_FAIL(ps_sql_meta_.deep_copy(other.get_ps_sql_meta()))) { LOG_WARN("deep copy ps sql meta faield", K(ret)); } } return ret; } int ObPsStmtInfo::add_column_field(const ObField& field) { int ret = OB_SUCCESS; if (OB_FAIL(ps_sql_meta_.add_column_field(field))) { LOG_WARN("add column field failed", K(ret)); } return ret; } int ObPsStmtInfo::add_param_field(const ObField& param) { int ret = OB_SUCCESS; if (OB_FAIL(ps_sql_meta_.add_param_field(param))) { LOG_WARN("add param field failed", K(ret)); } return ret; } int ObPsStmtInfo::get_convert_size(int64_t& cv_size) const { int ret = OB_SUCCESS; cv_size = 0; int64_t convert_size = sizeof(ObPsStmtInfo); convert_size += ps_sql_.length() + 1; int64_t meta_convert_size = 0; if (OB_FAIL(ps_sql_meta_.get_convert_size(meta_convert_size))) { LOG_WARN("get sql meta convert size failed", K(ret)); } if (OB_SUCC(ret)) { convert_size += meta_convert_size; convert_size += dep_objs_cnt_ * sizeof(share::schema::ObSchemaObjVersion); cv_size = convert_size; } return ret; } bool ObPsStmtInfo::check_erase_inc_ref_count() { bool need_erase = false; bool cas_ret = false; do { need_erase = false; int64_t cur_ref_cnt = ATOMIC_LOAD(&ref_count_); int64_t next_ref_cnt = cur_ref_cnt + 1; if (0 == cur_ref_cnt) { need_erase = true; break; } cas_ret = ATOMIC_BCAS(&ref_count_, cur_ref_cnt, next_ref_cnt); LOG_TRACE("ps info check erase inc ref count after cas", K(cur_ref_cnt), K(next_ref_cnt), K(cas_ret)); } while (!cas_ret); LOG_TRACE("ps info inc ref count", K(*this), K(need_erase)); return need_erase; } bool ObPsStmtInfo::dec_ref_count_check_erase() { bool need_erase = false; LOG_TRACE("ps info dec ref count", K(*this)); int64_t ref_count = ATOMIC_SAF(&ref_count_, 1); if (ref_count > 0) { if (ref_count == 1) { last_closed_timestamp_ = common::ObTimeUtility::current_time(); } LOG_TRACE("ps info dec ref count", K(ref_count), K(*this)); } else if (0 == ref_count) { need_erase = true; LOG_INFO("free ps info", K(ref_count), K(*this), K(need_erase)); } else if (ref_count < 0) { BACKTRACE(ERROR, true, "ObPsStmtInfo %p ref count < 0, ref_count = %ld", this, ref_count); } return need_erase; } int64_t ObPsStmtInfo::to_string(char* buf, const int64_t buf_len) const { int64_t pos = 0; int ret = OB_SUCCESS; J_OBJ_START(); J_KV(K_(db_id), K_(ps_sql), K_(ref_count), K_(can_direct_use_param), K_(question_mark_count), K_(last_closed_timestamp), K_(tenant_version)); J_COMMA(); J_NAME("columns"); J_COLON(); J_ARRAY_START(); for (int64_t i = 0; OB_SUCC(ret) && i < ps_sql_meta_.get_column_fields().count(); ++i) { J_KV("column", ps_sql_meta_.get_column_fields().at(i)); } J_ARRAY_END(); J_COMMA(); J_NAME("params"); J_COLON(); J_ARRAY_START(); for (int64_t i = 0; OB_SUCC(ret) && i < ps_sql_meta_.get_param_fields().count(); ++i) { J_KV("params", ps_sql_meta_.get_param_fields().at(i)); } J_ARRAY_END(); J_OBJ_END(); return pos; } ObPsStmtInfoGuard::~ObPsStmtInfoGuard() { int ret = OB_SUCCESS; if (NULL != ps_cache_) { if (NULL != stmt_info_) { if (OB_FAIL(ps_cache_->deref_stmt_info(stmt_id_))) { LOG_WARN("deref stmt item faield", K(ret), K(*stmt_info_), K_(stmt_id)); } LOG_TRACE("destroy PsStmtInfo Guard", K_(stmt_id)); } else { LOG_WARN("stmt info is null", K(stmt_id_)); } } else { LOG_WARN("ps_cache is null", K(stmt_id_), K(stmt_info_)); } } int ObPsStmtInfoGuard::get_ps_sql(ObString& ps_sql) { int ret = OB_SUCCESS; if (OB_ISNULL(stmt_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt info is null", K(ret)); } else { ps_sql = stmt_info_->get_ps_sql(); } return ret; } int TypeInfo::deep_copy(common::ObIAllocator* allocator, const TypeInfo* other) { int ret = OB_SUCCESS; if (this != other) { CK(OB_NOT_NULL(allocator)); CK(OB_NOT_NULL(other)); OZ(ob_write_string(*allocator, other->relation_name_, relation_name_)); OZ(ob_write_string(*allocator, other->package_name_, package_name_)); OZ(ob_write_string(*allocator, other->type_name_, type_name_)); OX(elem_type_ = other->elem_type_); OX(is_elem_type_ = other->is_elem_type_); OX(is_basic_type_ = other->is_basic_type_); } return ret; } } // namespace sql } // namespace oceanbase