807 lines
27 KiB
C++
807 lines
27 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX SQL_ENG
|
|
|
|
#include "ob_expr.h"
|
|
#include "sql/ob_sql_utils.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
#include "sql/engine/expr/ob_expr_operator.h"
|
|
#include "sql/engine/expr/ob_expr_calc_partition_id.h"
|
|
#include "sql/engine/expr/ob_expr_extra_info_factory.h"
|
|
#include "sql/engine/expr/ob_datum_cast.h"
|
|
#include "sql/engine/expr/ob_expr_lob_utils.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
using namespace common;
|
|
namespace sql
|
|
{
|
|
|
|
// ObPrecision and ObLengthSemantics are union field in ObDatumMeta,
|
|
// need to be same size to make sure serialization works.
|
|
STATIC_ASSERT(sizeof(ObPrecision) == sizeof(ObLengthSemantics),
|
|
"size of ObPrecision and ObLengthSemantics mismatch");
|
|
|
|
OB_SERIALIZE_MEMBER(ObDatumMeta, type_, cs_type_, scale_, precision_);
|
|
|
|
|
|
ObEvalCtx::ObEvalCtx(ObExecContext &exec_ctx, ObIAllocator *allocator)
|
|
: frames_(exec_ctx.get_frames()),
|
|
max_batch_size_(0),
|
|
exec_ctx_(exec_ctx),
|
|
tmp_alloc_(exec_ctx.get_eval_tmp_allocator()),
|
|
datum_caster_(NULL),
|
|
tmp_alloc_used_(exec_ctx.get_tmp_alloc_used()),
|
|
batch_idx_(0),
|
|
batch_size_(0),
|
|
expr_res_alloc_((dynamic_cast<ObArenaAllocator*>(allocator) != NULL) ? (*(dynamic_cast<ObArenaAllocator*>(allocator))) : exec_ctx.get_eval_res_allocator())
|
|
{
|
|
}
|
|
|
|
ObEvalCtx::ObEvalCtx(ObEvalCtx &eval_ctx)
|
|
: frames_(eval_ctx.frames_),
|
|
max_batch_size_(eval_ctx.max_batch_size_),
|
|
exec_ctx_(eval_ctx.exec_ctx_),
|
|
tmp_alloc_(eval_ctx.tmp_alloc_),
|
|
datum_caster_(NULL),
|
|
tmp_alloc_used_(eval_ctx.tmp_alloc_used_),
|
|
batch_idx_(eval_ctx.get_batch_idx()),
|
|
batch_size_(eval_ctx.get_batch_size()),
|
|
expr_res_alloc_(eval_ctx.expr_res_alloc_)
|
|
{
|
|
}
|
|
|
|
ObEvalCtx::~ObEvalCtx()
|
|
{
|
|
if (NULL != datum_caster_) {
|
|
datum_caster_->destroy();
|
|
datum_caster_ = NULL;
|
|
}
|
|
}
|
|
|
|
int ObEvalCtx::init_datum_caster()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (NULL == datum_caster_) {
|
|
ObDatumCaster *datum_caster = NULL;
|
|
void *buf = NULL;
|
|
if (OB_ISNULL(buf = exec_ctx_.get_allocator().alloc(sizeof(ObDatumCaster)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("alloc memory failed", K(ret));
|
|
} else if (FALSE_IT(datum_caster = new(buf) ObDatumCaster())) {
|
|
} else if (OB_FAIL(datum_caster->init(exec_ctx_))) {
|
|
LOG_WARN("init datum caster failed", K(ret));
|
|
} else {
|
|
datum_caster_ = datum_caster;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
DEF_TO_STRING(ObEvalInfo)
|
|
{
|
|
int64_t pos = 0;
|
|
J_OBJ_START();
|
|
J_KV(K_(evaluated), K_(projected), K_(notnull), K_(point_to_frame), K_(cnt));
|
|
J_OBJ_END();
|
|
return pos;
|
|
}
|
|
|
|
OB_DEF_SERIALIZE(ObExpr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LST_DO_CODE(OB_UNIS_ENCODE,
|
|
type_,
|
|
datum_meta_,
|
|
obj_meta_,
|
|
max_length_,
|
|
obj_datum_map_,
|
|
ser_eval_func_,
|
|
serialization::make_ser_carray(ser_inner_functions_, inner_func_cnt_),
|
|
serialization::make_ser_carray(args_, arg_cnt_),
|
|
serialization::make_ser_carray(parents_, parent_cnt_),
|
|
frame_idx_,
|
|
datum_off_,
|
|
res_buf_off_,
|
|
res_buf_len_,
|
|
expr_ctx_id_,
|
|
extra_);
|
|
|
|
LST_DO_CODE(OB_UNIS_ENCODE,
|
|
eval_info_off_,
|
|
flag_,
|
|
ser_eval_batch_func_,
|
|
eval_flags_off_,
|
|
pvt_skip_off_);
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ObExprOperatorType type = T_INVALID;
|
|
if (nullptr != extra_info_) {
|
|
type = extra_info_->type_;
|
|
}
|
|
// Add a type before extra_info to determine whether extra_info is empty
|
|
OB_UNIS_ENCODE(type)
|
|
if (OB_FAIL(ret)) {
|
|
} else if (T_INVALID != type) {
|
|
OB_UNIS_ENCODE(*extra_info_);
|
|
}
|
|
OB_UNIS_ENCODE(dyn_buf_header_offset_)
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
OB_DEF_DESERIALIZE(ObExpr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LST_DO_CODE(OB_UNIS_DECODE,
|
|
type_,
|
|
datum_meta_,
|
|
obj_meta_,
|
|
max_length_,
|
|
obj_datum_map_,
|
|
ser_eval_func_,
|
|
serialization::make_ser_carray(ser_inner_functions_, inner_func_cnt_),
|
|
serialization::make_ser_carray(args_, arg_cnt_),
|
|
serialization::make_ser_carray(parents_, parent_cnt_),
|
|
frame_idx_,
|
|
datum_off_,
|
|
res_buf_off_,
|
|
res_buf_len_,
|
|
expr_ctx_id_,
|
|
extra_);
|
|
|
|
LST_DO_CODE(OB_UNIS_DECODE,
|
|
eval_info_off_,
|
|
flag_,
|
|
ser_eval_batch_func_,
|
|
eval_flags_off_,
|
|
pvt_skip_off_);
|
|
if (0 == eval_info_off_ && OB_SUCC(ret)) {
|
|
// compatible with 3.0, ObExprDatum::flag_ is ObEvalInfo
|
|
eval_info_off_ = datum_off_ + sizeof(ObDatum);
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ObExprOperatorType type = T_INVALID;
|
|
// Add a type before extra_info to determine whether extra_info is empty
|
|
OB_UNIS_DECODE(type);
|
|
if (OB_FAIL(ret)) {
|
|
} else if (T_INVALID != type) {
|
|
OZ (ObExprExtraInfoFactory::alloc(CURRENT_CONTEXT->get_arena_allocator(),
|
|
type, extra_info_));
|
|
CK (OB_NOT_NULL(extra_info_));
|
|
OB_UNIS_DECODE(*extra_info_);
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
basic_funcs_ = ObDatumFuncs::get_basic_func(datum_meta_.type_, datum_meta_.cs_type_, datum_meta_.scale_,
|
|
lib::is_oracle_mode(), obj_meta_.has_lob_header());
|
|
CK(NULL != basic_funcs_);
|
|
}
|
|
if (is_batch_result()) {
|
|
batch_idx_mask_ = UINT64_MAX;
|
|
}
|
|
OB_UNIS_DECODE(dyn_buf_header_offset_);
|
|
return ret;
|
|
}
|
|
|
|
OB_DEF_SERIALIZE_SIZE(ObExpr)
|
|
{
|
|
int64_t len = 0;
|
|
LST_DO_CODE(OB_UNIS_ADD_LEN,
|
|
type_,
|
|
datum_meta_,
|
|
obj_meta_,
|
|
max_length_,
|
|
obj_datum_map_,
|
|
ser_eval_func_,
|
|
serialization::make_ser_carray(ser_inner_functions_, inner_func_cnt_),
|
|
serialization::make_ser_carray(args_, arg_cnt_),
|
|
serialization::make_ser_carray(parents_, parent_cnt_),
|
|
frame_idx_,
|
|
datum_off_,
|
|
res_buf_off_,
|
|
res_buf_len_,
|
|
expr_ctx_id_,
|
|
extra_);
|
|
|
|
LST_DO_CODE(OB_UNIS_ADD_LEN,
|
|
eval_info_off_,
|
|
flag_,
|
|
ser_eval_batch_func_,
|
|
eval_flags_off_,
|
|
pvt_skip_off_);
|
|
|
|
ObExprOperatorType type = T_INVALID;
|
|
if (nullptr != extra_info_) {
|
|
type = extra_info_->type_;
|
|
}
|
|
OB_UNIS_ADD_LEN(type);
|
|
if (T_INVALID != type) {
|
|
OB_UNIS_ADD_LEN(*extra_info_);
|
|
}
|
|
OB_UNIS_ADD_LEN(dyn_buf_header_offset_);
|
|
return len;
|
|
}
|
|
|
|
ObExpr::ObExpr()
|
|
: magic_(MAGIC_NUM),
|
|
type_(T_INVALID),
|
|
datum_meta_(),
|
|
obj_meta_(),
|
|
max_length_(UINT32_MAX),
|
|
obj_datum_map_(OBJ_DATUM_NULL),
|
|
flag_(0),
|
|
eval_func_(NULL),
|
|
eval_batch_func_(NULL),
|
|
inner_functions_(NULL),
|
|
inner_func_cnt_(0),
|
|
args_(NULL),
|
|
arg_cnt_(0),
|
|
parents_(NULL),
|
|
parent_cnt_(0),
|
|
frame_idx_(0),
|
|
datum_off_(0),
|
|
eval_info_off_(0),
|
|
dyn_buf_header_offset_(0),
|
|
res_buf_off_(0),
|
|
res_buf_len_(0),
|
|
eval_flags_off_(0),
|
|
pvt_skip_off_(0),
|
|
expr_ctx_id_(INVALID_EXP_CTX_ID),
|
|
extra_(0),
|
|
basic_funcs_(NULL),
|
|
batch_idx_mask_(0),
|
|
extra_info_(NULL)
|
|
{
|
|
is_called_in_sql_ = 1;
|
|
}
|
|
|
|
char *ObExpr::alloc_str_res_mem(ObEvalCtx &ctx, const int64_t size, const int64_t idx) const
|
|
{
|
|
char *mem = NULL;
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(!ObDynReserveBuf::supported(datum_meta_.type_))) {
|
|
LOG_ERROR("unexpected alloc string result memory called", K(size), K(*this));
|
|
} else {
|
|
ObDynReserveBuf *drb = reinterpret_cast<ObDynReserveBuf *>(
|
|
ctx.frames_[frame_idx_] + dyn_buf_header_offset_ + sizeof(ObDynReserveBuf) * idx);
|
|
if (OB_LIKELY(drb->len_ >= size)) {
|
|
mem = drb->mem_;
|
|
} else {
|
|
const int64_t alloc_size = next_pow2(size);
|
|
if (OB_UNLIKELY(alloc_size > UINT32_MAX)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(size), K(alloc_size), K(ret));
|
|
} else if (OB_ISNULL(mem = static_cast<char *>(ctx.alloc_expr_res(alloc_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate memory failed", K(ret), K(ret));
|
|
} else {
|
|
// When extend memory, the old memory can not free, because the old memory may
|
|
// still be referenced. see: ob_datum_cast.cpp::common_copy_string
|
|
if (0 == drb->len_) {
|
|
drb->magic_ = ObDynReserveBuf::MAGIC_NUM;
|
|
}
|
|
drb->len_ = alloc_size;
|
|
drb->mem_ = mem;
|
|
}
|
|
LOG_DEBUG("extend expr result memory",
|
|
K(ret), K(size), K(alloc_size), KP(this), KP(mem));
|
|
}
|
|
}
|
|
return mem;
|
|
};
|
|
|
|
|
|
int ObExpr::eval_enumset(ObEvalCtx &ctx,
|
|
const common::ObIArray<common::ObString> &str_values, const uint64_t cast_mode,
|
|
common::ObDatum *&datum) const
|
|
{
|
|
// performance critical, do not check %frame_idx_ and %frame again. (checked in CG)
|
|
int ret = common::OB_SUCCESS;
|
|
char *frame = ctx.frames_[frame_idx_];
|
|
OB_ASSERT(NULL != frame);
|
|
datum = (ObDatum *)(frame + datum_off_);
|
|
ObEvalInfo *eval_info = (ObEvalInfo *)(frame + eval_info_off_);
|
|
const common::ObObjTypeClass in_tc = args_[0]->obj_meta_.get_type_class();
|
|
EvalEnumSetFunc eval_func;
|
|
|
|
// do nothing for const/column reference expr or already evaluated expr
|
|
if (is_batch_result()) {
|
|
// Evaluate one datum within a batch.
|
|
bool need_evaluate = false;
|
|
if (eval_info->projected_){
|
|
datum = datum + ctx.get_batch_idx();
|
|
} else {
|
|
ObBitVector* evaluated_flags = to_bit_vector(frame + eval_flags_off_);
|
|
if (!eval_info->evaluated_) {
|
|
evaluated_flags->reset(ctx.get_batch_size());
|
|
reset_datums_ptr(frame, ctx.get_batch_size());
|
|
eval_info->evaluated_ = true;
|
|
eval_info->cnt_ = ctx.get_batch_size();
|
|
eval_info->point_to_frame_ = true;
|
|
eval_info->notnull_ = true;
|
|
}
|
|
if (!evaluated_flags->at(ctx.get_batch_idx())) {
|
|
need_evaluate = true;
|
|
}
|
|
datum = reinterpret_cast<ObDatum *>(frame + datum_off_) + ctx.get_batch_idx();
|
|
if (need_evaluate) {
|
|
if (OB_FAIL(ObDatumCast::get_enumset_cast_function(in_tc, obj_meta_.get_type(), eval_func))) {
|
|
LOG_WARN("failed to find eval_func", K(ret));
|
|
} else {
|
|
ret = eval_func(*this, str_values, cast_mode, ctx, *datum);
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
evaluated_flags->set(ctx.get_batch_idx());
|
|
} else {
|
|
datum->set_null();
|
|
}
|
|
if (datum->is_null()) {
|
|
eval_info->notnull_ = false;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (!eval_info->evaluated_) {
|
|
if (datum->ptr_ != frame + res_buf_off_) {
|
|
datum->ptr_ = frame + res_buf_off_;
|
|
}
|
|
if (OB_FAIL(ObDatumCast::get_enumset_cast_function(in_tc, obj_meta_.get_type(), eval_func))) {
|
|
SQL_LOG(WARN, "fail to get_enumset_cast_function", K(ret));
|
|
} else {
|
|
ret = eval_func(*this, str_values, cast_mode, ctx, *datum);
|
|
}
|
|
|
|
if (OB_LIKELY(common::OB_SUCCESS == ret)) {
|
|
eval_info->evaluated_ = true;
|
|
} else {
|
|
datum->set_null();
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
void *ObExprStrResAlloc::alloc(const int64_t size)
|
|
{
|
|
void *mem = expr_.get_str_res_mem(ctx_, off_ + size);
|
|
if (NULL != mem) {
|
|
mem = static_cast<char *>(mem) + off_;
|
|
off_ += size;
|
|
}
|
|
return mem;
|
|
}
|
|
|
|
int ObDatumObjParam::from_objparam(const ObObjParam &objparam, ObIAllocator *allocator) {
|
|
int ret = OB_SUCCESS;
|
|
meta_ = ObDatumMeta(objparam.meta_.get_type(),
|
|
objparam.meta_.get_collation_type(),
|
|
objparam.meta_.get_scale());
|
|
if (OB_UNLIKELY(objparam.is_ext_sql_array())) {
|
|
if (OB_ISNULL(allocator)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("construct array param datum need allocator", K(ret));
|
|
} else if (OB_FAIL(construct_array_param_datum(objparam, *allocator))) {
|
|
LOG_WARN("construct array param datum", K(ret));
|
|
}
|
|
} else if (OB_FAIL(datum_.from_obj(objparam))) {
|
|
LOG_WARN("fail to init datum", K(objparam), K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
accuracy_ = objparam.get_accuracy();
|
|
res_flags_ = objparam.get_result_flag();
|
|
flag_ = objparam.get_param_flag();
|
|
if (objparam.has_lob_header()) {
|
|
set_result_flag(HAS_LOB_HEADER_FLAG);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObDatumObjParam::to_objparam(common::ObObjParam &obj_param, ObIAllocator *allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObObjMeta meta;
|
|
meta.set_type(meta_.type_);
|
|
meta.set_collation_type(meta_.cs_type_);
|
|
meta.set_scale(meta_.scale_);
|
|
if (res_flags_ & HAS_LOB_HEADER_FLAG) {
|
|
meta.set_has_lob_header();
|
|
}
|
|
if (OB_UNLIKELY(meta_.is_ext_sql_array())) {
|
|
if (OB_ISNULL(allocator)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("construct sql array obj need allocator", K(ret));
|
|
} else if (OB_FAIL(construct_sql_array_obj(obj_param, *allocator))) {
|
|
LOG_WARN("construct sql array obj failed", K(ret));
|
|
}
|
|
} else if (OB_FAIL(datum_.to_obj(obj_param, meta))) {
|
|
LOG_WARN("failed to transform datum to obj", K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
obj_param.set_accuracy(accuracy_);
|
|
obj_param.set_result_flag(res_flags_);
|
|
obj_param.set_param_flag(flag_);
|
|
obj_param.set_param_meta();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObDatumObjParam::construct_array_param_datum(const ObObjParam &obj_param, ObIAllocator &allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(obj_param.is_ext_sql_array())) {
|
|
ObSqlDatumArray *datum_array = NULL;
|
|
const ObSqlArrayObj *array_obj = reinterpret_cast<const ObSqlArrayObj*>(obj_param.get_ext());
|
|
datum_array = ObSqlDatumArray::alloc(allocator, array_obj->count_);
|
|
if (OB_ISNULL(datum_array)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate datum array buffer failed", K(ret));
|
|
} else {
|
|
datum_array->element_ = array_obj->element_;
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < array_obj->count_; ++i) {
|
|
// 每一个datum数据都有自己的类型,datum_array->element_不再准确,但是这个只适用于insert values场景
|
|
ObObjDatumMapType obj_datum_map = ObDatum::get_obj_datum_map_type(
|
|
array_obj->data_[i].get_type());
|
|
if (OB_LIKELY(OBJ_DATUM_NULL != obj_datum_map)) {
|
|
uint32_t def_res_len = ObDatum::get_reserved_size(obj_datum_map);
|
|
if (OB_ISNULL(datum_array->data_[i].ptr_ = static_cast<char *>(allocator.alloc(def_res_len)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(def_res_len), K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(datum_array->data_[i].from_obj(array_obj->data_[i]))) {
|
|
LOG_WARN("fail to convert obj param", K(ret), K(array_obj->data_[i]));
|
|
} else {
|
|
LOG_DEBUG("construct datum array", K(array_obj->data_[i]), K(datum_array->data_[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
//you can't use datum_.extend_obj_ here, datum_.extend_obj_m is just to asign an ObObj pointer
|
|
//here you need to set the address of the constructed datum array
|
|
datum_.set_int(reinterpret_cast<int64_t>(datum_array));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObDatumObjParam::construct_sql_array_obj(ObObjParam &obj_param, ObIAllocator &allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(meta_.is_ext_sql_array())) {
|
|
//you can't call get_ext() here, get_ext() in Datum is to get an ObObj pointer
|
|
//here you need to get the address of the constructed datum array
|
|
const ObSqlDatumArray *datum_array = reinterpret_cast<const ObSqlDatumArray *>(datum_.get_int());
|
|
ObSqlArrayObj *array_obj = ObSqlArrayObj::alloc(allocator, datum_array->count_);
|
|
if (OB_ISNULL(array_obj)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate array buffer failed", K(ret), K(datum_array->count_));
|
|
} else {
|
|
array_obj->element_ = datum_array->element_;
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < datum_array->count_; ++i) {
|
|
if (OB_FAIL(datum_array->data_[i].to_obj(array_obj->data_[i],
|
|
datum_array->element_.get_meta_type()))) {
|
|
LOG_WARN("fail to convert obj param", K(ret), K(datum_array->data_[i]));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
obj_param.set_extend(reinterpret_cast<int64_t>(array_obj), T_EXT_SQL_ARRAY);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
DEF_TO_STRING(ObToStringDatum)
|
|
{
|
|
ObObj obj;
|
|
int ret = d_.to_obj(obj, e_.obj_meta_);
|
|
UNUSED(ret);
|
|
return obj.to_string(buf, buf_len);
|
|
}
|
|
|
|
DEF_TO_STRING(ObToStringExpr)
|
|
{
|
|
int64_t pos = 0;
|
|
if (c_.is_vectorized() && c_.get_batch_size() <= 0) {
|
|
// vectorize execution but batch_size not specified, do nothing
|
|
J_OBJ_START();
|
|
J_KV("Expr print ERROR", "vectorize execution but batch_size not specified");
|
|
J_OBJ_END();
|
|
} else if (c_.is_vectorized() && c_.get_batch_size() > 0 &&
|
|
c_.get_batch_idx() >= c_.get_batch_size()) {
|
|
// vectorize execution but batch_idx is not set correctly, do nothing
|
|
J_OBJ_START();
|
|
J_KV("Expr print ERROR", "vectorize execution but batch_idx is not set correctly");
|
|
J_COMMA();
|
|
J_KV("batch_idx", c_.get_batch_idx());
|
|
J_OBJ_END();
|
|
} else {
|
|
ObDatum *datum = NULL;
|
|
int ret = e_.eval(c_, datum);
|
|
UNUSED(ret);
|
|
pos = ObToStringDatum(e_, *datum).to_string(buf, buf_len);
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
DEF_TO_STRING(ObToStringExprRow)
|
|
{
|
|
int64_t pos = 0;
|
|
J_ARRAY_START();
|
|
for (int64_t i = 0; i < exprs_.count(); i++) {
|
|
ObExpr *expr = exprs_.at(i);
|
|
if (OB_LIKELY(expr != NULL)) {
|
|
J_OBJ_START();
|
|
J_KV(KP(expr));
|
|
J_COMMA();
|
|
pos += ObToStringExpr(c_, *expr).to_string(buf + pos, buf_len - pos);
|
|
J_OBJ_END();
|
|
} else {
|
|
J_OBJ_START();
|
|
J_OBJ_END();
|
|
}
|
|
if (i != exprs_.count() - 1) {
|
|
J_COMMA();
|
|
}
|
|
}
|
|
J_ARRAY_END();
|
|
return pos;
|
|
}
|
|
|
|
void ObExpr::reset_datums_ptr(char *frame, const int64_t size) const
|
|
{
|
|
// TODO bin.lb: on reset ptr from info->cnt_ to size if info->point_to_frame_ ?
|
|
ObDatum *datum = reinterpret_cast<ObDatum *>(frame + datum_off_);
|
|
ObDatum *datum_end = datum + size;
|
|
char *ptr = frame + res_buf_off_;
|
|
for (; datum < datum_end; datum += 1) {
|
|
if (datum->ptr_ != ptr) {
|
|
datum->ptr_ = ptr;
|
|
}
|
|
ptr += res_buf_len_;
|
|
}
|
|
}
|
|
|
|
void ObExpr::reset_datum_ptr(char *frame, const int64_t size, const int64_t idx) const
|
|
{
|
|
ObDatum *datum = reinterpret_cast<ObDatum *>(frame + datum_off_);
|
|
datum += idx;
|
|
char *ptr = frame + res_buf_off_ + (batch_idx_mask_ & idx) * res_buf_len_;
|
|
if (datum->ptr_ != ptr && idx < size) {
|
|
datum->ptr_ = ptr;
|
|
}
|
|
}
|
|
|
|
int ObExpr::eval_one_datum_of_batch(ObEvalCtx &ctx, common::ObDatum *&datum) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char *frame = ctx.frames_[frame_idx_];
|
|
ObEvalInfo *info = reinterpret_cast<ObEvalInfo *>(frame + eval_info_off_);
|
|
bool need_evaluate = false;
|
|
|
|
if (info->projected_ || NULL == eval_func_) {
|
|
// do nothing
|
|
} else if (!info->evaluated_) {
|
|
need_evaluate = true;
|
|
to_bit_vector(frame + eval_flags_off_)->reset(ctx.get_batch_size());
|
|
reset_datums_ptr(frame, ctx.get_batch_size());
|
|
info->evaluated_ = true;
|
|
info->cnt_ = ctx.get_batch_size();
|
|
info->point_to_frame_ = true;
|
|
info->notnull_ = true;
|
|
} else {
|
|
ObBitVector *evaluated_flags = to_bit_vector(frame + eval_flags_off_);
|
|
if (!evaluated_flags->at(ctx.get_batch_idx())) {
|
|
need_evaluate = true;
|
|
}
|
|
}
|
|
datum = reinterpret_cast<ObDatum *>(frame + datum_off_) + ctx.get_batch_idx();
|
|
if (need_evaluate) {
|
|
if (OB_UNLIKELY(need_stack_check_) && OB_FAIL(check_stack_overflow())) {
|
|
SQL_LOG(WARN, "failed to check stack overflow", K(ret));
|
|
} else {
|
|
reset_datum_ptr(frame, ctx.get_batch_size(), ctx.get_batch_idx());
|
|
ret = eval_func_(*this, ctx, *datum);
|
|
CHECK_STRING_LENGTH((*this), (*datum));
|
|
if (OB_SUCC(ret)) {
|
|
ObBitVector *evaluated_flags = to_bit_vector(frame + eval_flags_off_);
|
|
evaluated_flags->set(ctx.get_batch_idx());
|
|
} else {
|
|
datum->set_null();
|
|
}
|
|
if (datum->is_null()) {
|
|
info->notnull_ = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExpr::do_eval_batch(ObEvalCtx &ctx,
|
|
const ObBitVector &skip,
|
|
const int64_t size) const
|
|
{
|
|
|
|
int ret = OB_SUCCESS;
|
|
char *frame = ctx.frames_[frame_idx_];
|
|
ObEvalInfo *info = reinterpret_cast<ObEvalInfo *>(frame + eval_info_off_);
|
|
bool need_evaluate = false;
|
|
if (info->projected_ || NULL == eval_batch_func_) {
|
|
// expr values is projected by child or has no evaluate func, do nothing.
|
|
} else if (!info->evaluated_) {
|
|
need_evaluate = true;
|
|
to_bit_vector(frame + eval_flags_off_)->reset(size);
|
|
} else {
|
|
// check all datum evaluated
|
|
const ObBitVector *evaluated_vec = to_bit_vector(frame + eval_flags_off_);
|
|
need_evaluate = !ObBitVector::bit_op_zero(
|
|
skip, *evaluated_vec, size,
|
|
[](const uint64_t l, const uint64_t r) { return ~(l | r); });
|
|
}
|
|
|
|
if (need_evaluate) {
|
|
// Set ObDatum::ptr_ point to reserved buffer in the first evaluation.
|
|
// FIXME bin.lb: maybe we can optimize this by ObEvalInfo::point_to_frame_
|
|
if (!info->evaluated_) {
|
|
reset_datums_ptr(frame, size);
|
|
info->notnull_ = false;
|
|
info->point_to_frame_ = true;
|
|
}
|
|
if (OB_UNLIKELY(need_stack_check_) && OB_FAIL(check_stack_overflow())) {
|
|
SQL_LOG(WARN, "failed to check stack overflow", K(ret));
|
|
} else {
|
|
ret = (*eval_batch_func_)(*this, ctx, skip, size);
|
|
if (OB_SUCC(ret)) {
|
|
if (!info->evaluated_) {
|
|
info->cnt_ = size;
|
|
info->evaluated_ = true;
|
|
}
|
|
#ifndef NDEBUG
|
|
if (is_oracle_mode() && (ob_is_string_tc(datum_meta_.type_) || ob_is_raw(datum_meta_.type_))) {
|
|
ObDatum *datum = reinterpret_cast<ObDatum *>(frame + datum_off_);
|
|
for (int64_t i = 0; i < size; i++) {
|
|
if (!skip.contain(i) && 0 == datum[i].len_ && !datum[i].is_null()) {
|
|
SQL_ENG_LOG(ERROR, "unexpected datum length", KPC(this));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
} else {
|
|
ObDatum *datum = reinterpret_cast<ObDatum *>(frame + datum_off_);
|
|
ObDatum *datum_end = datum + size;
|
|
for (; datum < datum_end; datum += 1) {
|
|
datum->set_null();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int expr_default_eval_batch_func(const ObExpr &expr,
|
|
ObEvalCtx &ctx,
|
|
const ObBitVector &skip,
|
|
const int64_t size)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
char *frame = ctx.frames_[expr.frame_idx_];
|
|
ObBitVector *evaluated_flags = to_bit_vector(frame + expr.eval_flags_off_);
|
|
ObDatum *datum = reinterpret_cast<ObDatum *>(frame + expr.datum_off_);
|
|
ObEvalCtx::BatchInfoScopeGuard batch_info_guard(ctx);
|
|
batch_info_guard.set_batch_size(size);
|
|
bool got_null = false;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < size; i++) {
|
|
if (!skip.contain(i) && !evaluated_flags->contain(i)) {
|
|
// set current evaluate index
|
|
batch_info_guard.set_batch_idx(i);
|
|
ret = expr.eval_func_(expr, ctx, datum[i]);
|
|
CHECK_STRING_LENGTH(expr, datum[i]);
|
|
evaluated_flags->set(i);
|
|
if (datum[i].is_null()) {
|
|
got_null = true;
|
|
}
|
|
}
|
|
}
|
|
// reset evaluate index
|
|
if (got_null) {
|
|
expr.get_eval_info(ctx).notnull_ = false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int eval_question_mark_func(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(ctx.exec_ctx_.get_physical_plan_ctx())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("NULL plan ctx", K(ret));
|
|
} else {
|
|
const auto ¶m_store = ctx.exec_ctx_.get_physical_plan_ctx()->get_param_store();
|
|
if (expr.extra_ >= param_store.count()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid param store idx", K(ret), K(expr), K(param_store.count()));
|
|
} else {
|
|
const ObObj &v = param_store.at(expr.extra_);
|
|
if (v.get_type() != expr.datum_meta_.type_ && !v.is_null()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("obj type miss match", K(ret), K(v), K(expr));
|
|
} else if (OB_FAIL(expr_datum.from_obj(v, expr.obj_datum_map_))) {
|
|
LOG_WARN("set obj to datum failed", K(ret));
|
|
} else if (is_lob_storage(v.get_type()) &&
|
|
OB_FAIL(ob_adjust_lob_datum(v, expr.obj_meta_, expr.obj_datum_map_,
|
|
ctx.exec_ctx_.get_allocator(), expr_datum))) {
|
|
LOG_WARN("adjust lob datum failed", K(ret), K(v.get_meta()), K(expr.obj_meta_));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int eval_assign_question_mark_func(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
|
|
if (OB_ISNULL(session) || OB_ISNULL(ctx.exec_ctx_.get_physical_plan_ctx())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), KPC(session));
|
|
} else {
|
|
ObCastMode cast_mode = CM_NONE;
|
|
const auto ¶m_store = ctx.exec_ctx_.get_physical_plan_ctx()->get_param_store();
|
|
if (expr.extra_ >= param_store.count()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid param store idx", K(ret), K(expr), K(param_store.count()));
|
|
} else if (OB_FAIL(ObSQLUtils::get_default_cast_mode(
|
|
session->get_stmt_type(), session, cast_mode))) {
|
|
LOG_WARN("get default cast mode failed", K(ret));
|
|
} else {
|
|
ObObj dst_obj;
|
|
ObDatumObjParam datum_param;
|
|
const ObObj &v = param_store.at(expr.extra_);
|
|
const common::ObObjMeta dst_meta = expr.obj_meta_;
|
|
ObIAllocator &allocator = ctx.exec_ctx_.get_allocator();
|
|
const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(session);
|
|
cast_mode = lib::is_oracle_mode() ?
|
|
(cast_mode | CM_CHARSET_CONVERT_IGNORE_ERR) : (cast_mode | CM_COLUMN_CONVERT);
|
|
if (ctx.exec_ctx_.get_physical_plan_ctx()->is_ignore_stmt()) {
|
|
cast_mode = cast_mode | CM_WARN_ON_FAIL;
|
|
}
|
|
ObCastCtx cast_ctx(&allocator, &dtc_params, cast_mode, dst_meta.get_collation_type());
|
|
if (OB_FAIL(ObObjCaster::to_type(dst_meta.get_type(), cast_ctx, v, dst_obj))) {
|
|
LOG_WARN("failed to cast obj to dst type", K(ret), K(v), K(dst_meta));
|
|
} else if (OB_FAIL(datum_param.alloc_datum_reserved_buff(dst_meta, allocator))) {
|
|
LOG_WARN("alloc datum reserved buffer failed", K(ret));
|
|
} else if (OB_FAIL(datum_param.from_objparam(dst_obj, &allocator))) {
|
|
LOG_WARN("fail to convert obj param", K(ret), K(dst_obj));
|
|
} else {
|
|
expr_datum = datum_param.datum_;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} // end namespace sql
|
|
} // end namespace oceanbase
|