Files
oceanbase/src/sql/engine/expr/ob_expr_operator.cpp
2022-11-11 03:37:19 +00:00

6098 lines
239 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 "sql/engine/expr/ob_expr_operator.h"
#include <math.h>
#include "lib/oblog/ob_log.h"
//#include "sql/engine/expr/ob_expr_promotion_util.h"
#include "sql/engine/expr/ob_expr_result_type_util.h"
#include "sql/engine/expr/ob_expr_less_than.h"
#include "sql/engine/ob_physical_plan_ctx.h"
#include "sql/engine/expr/ob_expr_add.h"
#include "sql/engine/expr/ob_expr_minus.h"
#include "sql/engine/expr/ob_expr_subquery_ref.h"
#include "sql/engine/expr/ob_expr_null_safe_equal.h"
#include "sql/session/ob_sql_session_info.h"
#include "sql/engine/expr/ob_infix_expression.h"
#include "sql/code_generator/ob_static_engine_expr_cg.h"
#include "sql/engine/subquery/ob_subplan_filter_op.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/engine/expr/ob_expr_util.h"
#include "sql/engine/subquery/ob_subplan_filter_op.h"
#include "lib/timezone/ob_oracle_format_models.h"
namespace oceanbase
{
using namespace common;
using namespace common::number;
using namespace oceanbase::lib;
namespace sql
{
static const int32_t DAYS_PER_YEAR[2]=
{
365, 366
};
static const int8_t DAYS_PER_MON[2][12 + 1] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
#define IS_LEAP_YEAR(y) ((((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) ? 1 : 0)
const char *ObExprTRDateFormat::FORMATS_TEXT[FORMAT_MAX_TYPE] =
{
"SYYYY", "YYYY", "YEAR", "SYEAR", "YYY", "YY", "Y",
"IYYY", "IY", "I",
"Q",
"MONTH", "MON", "MM", "RM",
"WW",
"IW",
"W",
"DDD", "DD", "J",
"DAY", "DY", "D",
"HH", "HH12", "HH24",
"MI",
"CC","SCC"
};
uint64_t ObExprTRDateFormat::FORMATS_HASH[FORMAT_MAX_TYPE] = {0};
OB_SERIALIZE_MEMBER(ObFuncInputType, calc_meta_, max_length_, flag_);
OB_SERIALIZE_MEMBER_INHERIT(ObExprResType,
ObObjMeta,
accuracy_,
calc_accuracy_,
calc_type_,
res_flags_,
row_calc_cmp_types_);
const ObTimeZoneInfo *get_timezone_info(const ObSQLSessionInfo *session)
{
return TZ_INFO(session);
}
const common::ObObjPrintParams get_obj_print_params(const ObSQLSessionInfo *session)
{
return CREATE_OBJ_PRINT_PARAM(session);
}
int64_t get_cur_time(ObPhysicalPlanCtx *phy_plan_ctx)
{
return NULL != phy_plan_ctx ? phy_plan_ctx->get_cur_time().get_datetime() : 0;
}
int get_tz_offset(const ObTimeZoneInfo *tz_info, int64_t &offset)
{
int ret = OB_SUCCESS;
offset = 0;
int32_t tmp_offset = 0;
if (NULL != tz_info && OB_SUCC(tz_info->get_timezone_offset(0, tmp_offset))) {
offset = SEC_TO_USEC(tmp_offset);
}
return ret;
}
OB_SERIALIZE_MEMBER(ObExprOperator::DatumCastExtraInfo, cmp_meta_, cm_);
int ObExprOperator::DatumCastExtraInfo::deep_copy(common::ObIAllocator &allocator,
const ObExprOperatorType type,
ObIExprExtraInfo *&copied_info) const
{
int ret = OB_SUCCESS;
OZ(ObExprExtraInfoFactory::alloc(allocator, type, copied_info));
DatumCastExtraInfo &other = *static_cast<DatumCastExtraInfo *>(copied_info);
if (OB_SUCC(ret)) {
other = *this;
}
return ret;
}
int ObExprOperator::assign(const ObExprOperator &other)
{
int ret = OB_SUCCESS;
if (OB_LIKELY(this != &other)) {
if (OB_FAIL(result_type_.assign(other.result_type_))) {
LOG_WARN("copy result_type failed", K(ret));
} else if (OB_FAIL(input_types_.assign(other.input_types_))) {
LOG_WARN("copy input_types failed", K(ret));
} else {
this->magic_ = other.magic_;
this->id_ = other.id_;
this->row_dimension_ = other.row_dimension_;
this->real_param_num_ = other.real_param_num_;
this->is_called_in_sql_ = other.is_called_in_sql_;
this->extra_serialize_ = other.extra_serialize_;
}
}
return ret;
}
int ObExprOperator::cg_expr(ObExprCGCtx &,
const ObRawExpr &raw_expr,
ObExpr &) const
{
int ret = OB_NOT_SUPPORTED;
LOG_INFO("not implemented in sql static typing engine, ", K(ret), K(raw_expr));
return ret;
}
// check function pointer in vtable to detect cg_expr() is overwrite or not.
bool ObExprOperator::is_default_expr_cg() const
{
static ObArenaAllocator alloc;
static ObExprOperator base(alloc, T_NULL, "fake_null_operator", 0);
typedef int (ObExprOperator::*CGFunc)(
ObExprCGCtx &op_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const;
union {
CGFunc func_;
int64_t val_;
int64_t values_[2];
} func_val;
static_assert(sizeof(int64_t) * 2 == sizeof(CGFunc), "size mismatch");
func_val.func_ = &ObExprOperator::cg_expr;
const int64_t func_idx = func_val.val_ / sizeof(void *);
return (*(void ***)(&base))[func_idx] == (*(void ***)(this))[func_idx];
}
int ObExprOperator::set_input_types(const ObIExprResTypes &expr_types)
{
int ret = OB_SUCCESS;
input_types_.reset();
if (OB_FAIL(input_types_.reserve(expr_types.count()))) {
LOG_WARN("fail to init input types", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < expr_types.count(); ++i) {
const ObExprResType &t = expr_types.at(i);
ObFuncInputType type(t.get_calc_meta(), t.get_length(), t.get_result_flag());
ret = input_types_.push_back(type);
}
return ret;
}
ObObjType ObExprOperator::get_calc_cast_type(ObObjType param_type, ObObjType calc_type)
{
ObObjType cast_type = param_type;
if (ObNullType == param_type || ObNullType == calc_type) {
cast_type = param_type;
} else if (ObMaxType == param_type || ObMaxType == calc_type) {
cast_type = param_type;
} else if (ob_is_integer_type(param_type) && ob_is_integer_type(calc_type)) {
cast_type = param_type;
// } else if (ob_is_enumset_tc(param_type) && ob_is_enumset_numeric_type(calc_type)) {
// cast_type = param_type;
} else if (param_type != calc_type) {
cast_type = calc_type;
}
return cast_type;
}
int OB_INLINE ObExprOperator::cast_operand_type(common::ObObj &res_obj,
const ObFuncInputType &res_type,
common::ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
// check if need to cast
const ObObjType param_type = res_obj.get_type();
const ObObjType calc_type = res_type.get_calc_type();
const ObCollationType param_collation_type = res_obj.get_collation_type();
const ObCollationType calc_collation_type = res_type.get_calc_meta().get_collation_type();
if (OB_LIKELY((calc_type != param_type && ObNullType != param_type) ||
(ob_is_string_or_lob_type(param_type) &&
ob_is_string_or_lob_type(calc_type) &&
(lib::is_oracle_mode() || param_collation_type != calc_collation_type)))) {
LOG_DEBUG("need cast operand", K(res_type), K(res_type.get_calc_meta().get_scale()),
K(res_obj), K(res_obj.get_scale()));
ObCastMode cast_mode = get_cast_mode();
if (OB_UNLIKELY(T_FUN_PAD == get_type()
&& ob_is_bit_tc(param_type)
&& ob_is_varbinary_type(calc_type, calc_collation_type)
&& CM_IS_COLUMN_CONVERT(expr_ctx.column_conv_ctx_.cast_mode_))) {
// In PAD expression, we need add COLUMN_CONVERT to cast mode when cast is
// from bit to binary and column convert is set in column_conv_ctx_. The COLUMN_CONVERT
// cast mode is used in bit_to_string to decide which cast way is appropriate.
cast_mode |= CM_COLUMN_CONVERT;
} else if (OB_UNLIKELY(T_FUN_SYS_BIT_COUNT == get_type()
&& ObIntType == param_type
&& ObUInt64Type == calc_type)) {
// when param_type is ObIntType and calc_type is ObUInt64Type,
// set CM_NO_RANGE_CHECK in cast_mode,
// so that res_obj will not convert to zero even res_obj is less than 0.
cast_mode |= CM_NO_RANGE_CHECK;
}
bool is_bool = false;
ObItemType item_type = T_NULL;
if (lib::is_mysql_mode() && calc_type == ObJsonType && ob_obj_type_class(param_type) == ObIntTC) {
if (OB_FAIL(get_param_is_boolean(expr_ctx, res_obj, is_bool))) {
LOG_WARN("get src item type failed, bool may be cast as json int", K(res_obj), K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (is_bool) {
const ObObj *tmp_res_obj = NULL;
EXPR_DEFINE_CAST_CTX(expr_ctx, cast_mode);
if (CS_TYPE_INVALID != calc_collation_type) {
cast_ctx.dest_collation_ = calc_collation_type;
} else if (lib::is_mysql_mode() && CS_TYPE_INVALID != param_collation_type) {
cast_ctx.dest_collation_ = param_collation_type;
}
ret = ObObjCaster::bool_to_json(calc_type, cast_ctx, res_obj, res_obj, tmp_res_obj);
LOG_DEBUG("cast bool to json", K(cast_mode), K(calc_type), K(cast_ctx.dest_collation_), K(res_obj), K(ret));
} else if (ob_is_string_or_lob_type(res_type.get_calc_type()) && res_type.is_zerofill()) {
// For zerofilled string
ObZerofillInfo zf_info(true, res_type.get_length());
EXPR_DEFINE_CAST_CTX_ZF(expr_ctx, cast_mode, &zf_info);
if (OB_FAIL(ObObjCaster::to_type(res_type.get_calc_type(),
cast_ctx,
res_obj,
res_obj))) {
LOG_WARN("fail to convert type", K(ret),
K(res_type.get_calc_type()), K(res_obj));
}
} else {
// TODO: (jiuren, xiaochu) 更复杂的转换模式在这里实现
/* 类型转换collation设置逻辑如下:
* 1.cast_ctx中设置的目标collation是系统默认的collation,目前是utf8mb4
* 2.如果目标和源类型都是ObStringTC,根据以下逻辑设置:
* a.如果设置了calc_collation,使用该collation
* b.如果没有,使用源类型collation
*/
EXPR_DEFINE_CAST_CTX(expr_ctx, cast_mode);
if (ob_is_string_or_lob_type(calc_type)) {
if (ob_is_string_or_lob_type(param_type)) {
if (CS_TYPE_INVALID != calc_collation_type) {
cast_ctx.dest_collation_ = calc_collation_type;
} else if (lib::is_mysql_mode()
&& CS_TYPE_INVALID != param_collation_type) {
cast_ctx.dest_collation_ = param_collation_type;
}
} else {
if (CS_TYPE_INVALID != calc_collation_type) {
cast_ctx.dest_collation_ = calc_collation_type;
} else {
cast_ctx.dest_collation_ = ObCharset::get_default_collation_oracle(CHARSET_UTF8MB4);
}
}
} else if (lib::is_mysql_mode() && ob_is_json(calc_type)) {
cast_ctx.dest_collation_ = CS_TYPE_UTF8MB4_BIN;
}
// FIXME: (xiaochu) 就地修改obj类型算法没问题吧?
ObObj res_obj_copy = res_obj;
cast_ctx.expect_obj_collation_ = cast_ctx.dest_collation_;
if (OB_FAIL(ObObjCaster::to_type(res_type.get_calc_type(),
cast_ctx,
res_obj_copy,
res_obj))) {
LOG_WARN("fail to convert type", K(ret),
K(res_type.get_calc_type()), K(res_obj));
}
if (OB_SUCC(ret)
&& ob_is_string_or_lob_type(param_type)
&& ob_is_string_or_lob_type(calc_type)
&& param_collation_type != calc_collation_type
&& calc_collation_type != CS_TYPE_INVALID) {
res_obj.set_collation_type(calc_collation_type);
}
}
}
return ret;
}
int ObExprOperator::cast_operand_type(ObObj *params,
const int64_t param_num,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
/*
* TODO: (xiaochu)
* 1. Optimizer阶段为了计算partition index,会生造ObExprOperator,此时导致input_types_没有被初始化
* 2. cast和conv在CG阶段路径有点异常,还没搞清楚
* 3. 向量怎么搞,多行数据怎么搞?暂时先跳过,不转
*/
const bool fallback_old_mode = false;
if (OB_ISNULL(params) || OB_UNLIKELY(param_num < 0)
|| OB_UNLIKELY(param_num != real_param_num_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("NULL param or invalid number",
K(params), K(param_num), K(real_param_num_), K(ret));
} else if (fallback_old_mode) {
// fallback
} else if (OB_UNLIKELY(real_param_num_ <= 0 ||
0 == input_types_.count() ||
NOT_ROW_DIMENSION != row_dimension_ ||
/* insert default time, expr生成不规范 */
T_FUN_SYS_TIMESTAMP_NVL == get_type() /*||
T_FUN_SYS_CAST == get_type() ||
T_OP_CASE == get_type() ||
T_OP_ARG_CASE == get_type() ||
T_FUN_COLUMN_CONV == get_type()*/)) {
// skip
} else if (OB_UNLIKELY(input_types_.count() != real_param_num_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("real_param_num_ is wrong",K(input_types_.count()), K_(real_param_num));
} else {
// 转化Operator每一个参数的数据类型
// 仅当和目标类型不一致的时候才需要转换
for (int64_t i = 0; OB_SUCC(ret) && i < real_param_num_; ++i) {
if (OB_FAIL(cast_operand_type(params[i], input_types_.at(i), expr_ctx))) {
LOG_WARN("cast failed", K(ret), K(params[i]), K(input_types_.at(i)));
}
}
}
return ret;
}
int ObExprOperator::call(ObObj *stack, int64_t &stack_size, ObExprCtx &expr_ctx) const
{
ObObj result;
int ret = OB_SUCCESS;
if (OB_ISNULL(stack) || OB_ISNULL(this) || OB_UNLIKELY(real_param_num_ < 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("stack or this is null or stack_size is wrong", K(stack),
K(this), K(real_param_num_), K(ret));
} else if (OB_UNLIKELY(real_param_num_ > stack_size)) {
ret = OB_INVALID_ARGUMENT_NUM;
LOG_WARN("wrong number of input arguments on stack",
K(real_param_num_), K(stack_size), K(ret));
} else if (OB_LIKELY(row_dimension_ != NOT_ROW_DIMENSION)) {
int32_t param_num = real_param_num_ * row_dimension_;
if (OB_UNLIKELY(param_num > stack_size)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("wrong number of input arguments on stack", K(param_num), K(stack_size));
// vector operator
} else if (OB_FAIL(this->calc_resultN(result,
&stack[stack_size - param_num],
param_num,
expr_ctx))) {
LOG_WARN("fail to calc resultN", K(ret), K(param_num), K(stack_size));
} else {
stack[stack_size - param_num] = result;
stack_size -= (param_num - 1);
}
// FIXME: (xiaochu.yh) 有Row的情况下,不cast_operand_type,由用户自己处理?
} else if (operand_auto_cast_
&& OB_FAIL(cast_operand_type(stack + stack_size - real_param_num_,
real_param_num_, expr_ctx))) {
LOG_WARN("fail convert operand types", K(stack_size), K(ret));
} else {
if (OB_UNLIKELY(param_num_ > 0 && param_num_ != real_param_num_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("bug! param_num is not equal than real_param_num",
K_(name), K(get_type_name(type_)),
K_(type), K_(param_num), K_(real_param_num),
K_(row_dimension), K(input_types_.count()),
K(stack_size), K(ret));
}
if (OB_UNLIKELY(real_param_num_ < 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("bug! real_param_num is less than 0", K_(name), K(get_type_name(type_)),
K_(type), K_(param_num), K_(real_param_num),
K_(row_dimension), K(input_types_.count()),
K(stack_size), K(ret));
}
// 这里使用 @param_num_ 是因为它是一个和Operator类型绑定的静态值,
// Operator的定义中指定了它能接受的参数的个数。
// 对于concat、partition_key等函数来说,param_num_是一个负数,
// 提示call调用自己的calc_resultN方法
if (OB_SUCC(ret)) {
switch (param_num_) {
case 0: {
if (OB_FAIL(this->calc_result0(result, expr_ctx))) {
LOG_WARN("fail to calc result0", K(ret), K(stack_size));
} else {
stack[stack_size] = result;
++ stack_size;
}
break;
}
case 1: {
if (OB_FAIL(this->calc_result1(result, stack[stack_size - 1], expr_ctx))) {
LOG_WARN("fail to calc result1", K(ret), K(stack_size), N_FUNC, get_type_name(type_));
} else {
stack[stack_size - 1] = result;
}
break;
}
case 2: {
if (OB_FAIL(this->calc_result2(result,
stack[stack_size - 2],
stack[stack_size - 1],
expr_ctx))) {
LOG_WARN("fail to calc result2", K(ret), K(stack_size), N_FUNC, get_type_name(type_));
} else {
stack[stack_size - 2] = result;
stack_size--;
}
break;
}
case 3: {
// org mode
if (OB_FAIL(this->calc_result3(result,
stack[stack_size - 3],
stack[stack_size - 2],
stack[stack_size - 1],
expr_ctx))) {
LOG_WARN("fail to calc result3", K(ret), K(stack_size), N_FUNC, get_type_name(type_));
} else {
stack[stack_size - 3] = result;
stack_size -= 2;
}
break;
}
default: {
if (OB_FAIL(this->calc_resultN(result,
&stack[stack_size - real_param_num_],
real_param_num_,
expr_ctx))) {
LOG_WARN("fail to calc resultN", K(ret), K(stack_size), N_FUNC, get_type_name(type_));
} else {
stack[stack_size - real_param_num_] = result;
stack_size -= real_param_num_ - 1;
}
break;
}
} // end switch
if (!stack[stack_size - 1].is_bit()) {
stack[stack_size - 1].set_scale(result_type_.get_scale());
}
}
}
return ret;
}
int ObExprOperator::eval(common::ObExprCtx &expr_ctx, common::ObObj &val,
common::ObObj *params, int64_t param_num) const
{
int ret = OB_SUCCESS;
// some expr (e.g.: subtime) rely on the default value of ObObj, so we construct it again.
// (see ObExprOperator::calc(), use an new stack ObObj variable and assign to val finally).
new (&val) ObObj();
if (OB_ISNULL(params) || OB_UNLIKELY(param_num < 0)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else if (OB_UNLIKELY(row_dimension_ != NOT_ROW_DIMENSION)) {
// row operator
if (OB_FAIL(calc_resultN(val, params, param_num, expr_ctx))) {
LOG_WARN("calc result failed", K(ret), K(name_), K(get_type_name(type_)));
}
} else if (!is_param_lazy_eval() && operand_auto_cast_
&& OB_FAIL(cast_operand_type(params, param_num, expr_ctx))) {
LOG_WARN("cast operand failed", K(ret));
} else {
if (OB_UNLIKELY(param_num != real_param_num_)
|| OB_UNLIKELY(param_num_ > 0 && param_num_ != real_param_num_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("wrong param num", K(ret), K(param_num), K(param_num_), K(real_param_num_));
} else {
// Must use %param_num_, because it will set to negative number to indicate that
// we should call calc_resultN here. e.g.: concat
switch (param_num_) {
case 0: {
ret = calc_result0(val, expr_ctx);
break;
}
case 1: {
ret = calc_result1(val, params[0], expr_ctx);
break;
}
case 2: {
ret = calc_result2(val, params[0], params[1], expr_ctx);
break;
}
case 3: {
ret = calc_result3(val, params[0], params[1], params[2], expr_ctx);
break;
}
default: {
ret = calc_resultN(val, params, param_num, expr_ctx);
}
}
if (OB_FAIL(ret)) {
LOG_WARN("calc result failed", K(ret), K(param_num_), K(name_), K(get_type_name(type_)));
}
if (!val.is_bit() && !val.is_ext()) {
val.set_scale(result_type_.get_scale());
}
}
}
return ret;
}
int ObExprOperator::param_eval(common::ObExprCtx &expr_ctx,
const common::ObObj &param, const int64_t param_index) const
{
int ret = OB_SUCCESS;
if (OB_ISNULL(expr_ctx.infix_expr_)) {
// do nothing for postfix expression
} else {
if (OB_FAIL(expr_ctx.infix_expr_->param_eval(expr_ctx, param))) {
LOG_WARN("param eval failed", K(ret));
} else if (OB_LIKELY(row_dimension_ == NOT_ROW_DIMENSION)
&& OB_LIKELY(T_FUN_SYS_TIMESTAMP_NVL != type_)
&& OB_LIKELY(param_index) < input_types_.count()) {
// skip row operator and T_FUN_SYS_TIMESTAMP_NVL. (see cast_operand_type())
if (operand_auto_cast_ && OB_FAIL(cast_operand_type(const_cast<ObObj &>(param),
input_types_.at(param_index), expr_ctx))) {
LOG_WARN("cast failed", K(ret), K(param), K(input_types_.at(param_index)));
}
}
}
return ret;
}
int ObExprOperator::get_param_type(common::ObExprCtx &expr_ctx,
const common::ObObj &param, ObItemType &param_type) const
{
int ret = OB_SUCCESS;
if (OB_ISNULL(expr_ctx.infix_expr_)) {
// do nothing for postfix expression
} else {
if (OB_FAIL(expr_ctx.infix_expr_->get_param_type(expr_ctx, param, param_type))) {
LOG_WARN("param eval failed", K(ret));
}
}
return ret;
}
int ObExprOperator::get_param_is_boolean(common::ObExprCtx &expr_ctx,
const common::ObObj &param, bool &is_boolean) const
{
int ret = OB_SUCCESS;
is_boolean = false;
if (OB_ISNULL(expr_ctx.infix_expr_)) {
// do nothing for postfix expression
} else {
if (OB_FAIL(expr_ctx.infix_expr_->get_param_is_boolean(expr_ctx, param,
is_boolean))) {
LOG_WARN("get param bool semantics failed", K(ret));
}
}
return ret;
}
bool ObExprOperator::is_valid_nls_param(const common::ObString &nls_param_str)
{
bool bret = false;
if (!nls_param_str.empty() && NULL != nls_param_str.find('=')) {
static const common::ObString DEFAULT_VALUE_CALENDAR("GREGORIAN");
static const common::ObString DEFAULT_VALUE_DATE_LANGUAGE("AMERICAN");
static const common::ObString DEFAULT_VALUE_LANGUAGE("AMERICAN");
static const common::ObString DEFAULT_VALUE_NUMERIC_CHARACTERS(".,");
static const common::ObString DEFAULT_VALUE_SORT("BINARY");
static const common::ObString DEFAULT_VALUE_COMP("BINARY");
static const common::ObString DEFAULT_VALUE_CURRENCY("$");
static const common::ObString DEFAULT_VALUE_ISO_CURRENCY("AMERICA");
static const common::ObString DEFAULT_VALUE_DUAL_CURRENCY("$");
static const common::ObString DEFAULT_NAME_CALENDAR(share::OB_SV_NLS_CALENDAR);
static const common::ObString DEFAULT_NAME_DATE_LANGUAGE(share::OB_SV_NLS_DATE_LANGUAGE);
static const common::ObString DEFAULT_NAME_LANGUAGE(share::OB_SV_NLS_LANGUAGE);
static const common::ObString DEFAULT_NAME_NUMERIC_CHARACTERS(share::OB_SV_NLS_NUMERIC_CHARACTERS);
static const common::ObString DEFAULT_NAME_SORT(share::OB_SV_NLS_SORT);
static const common::ObString DEFAULT_NAME_COMP(share::OB_SV_NLS_COMP);
static const common::ObString DEFAULT_NAME_CURRENCY(share::OB_SV_NLS_CURRENCY);
static const common::ObString DEFAULT_NAME_ISO_CURRENCY(share::OB_SV_NLS_ISO_CURRENCY);
static const common::ObString DEFAULT_NAME_DUAL_CURRENCY(share::OB_SV_NLS_DUAL_CURRENCY);
ObString value_str = const_cast<common::ObString &>(nls_param_str).trim();
ObString name_str = value_str.split_on('=');
name_str = name_str.trim();
value_str = value_str.trim();
if (!name_str.empty() && !value_str.empty()) {
if ((0 == name_str.case_compare(DEFAULT_NAME_CALENDAR) && 0 == value_str.case_compare(DEFAULT_VALUE_CALENDAR))
|| (0 == name_str.case_compare(DEFAULT_NAME_DATE_LANGUAGE) && 0 == value_str.case_compare(DEFAULT_VALUE_DATE_LANGUAGE))
|| (0 == name_str.case_compare(DEFAULT_NAME_LANGUAGE) && 0 == value_str.case_compare(DEFAULT_VALUE_LANGUAGE))
|| (0 == name_str.case_compare(DEFAULT_NAME_NUMERIC_CHARACTERS) && 0 == value_str.case_compare(DEFAULT_VALUE_NUMERIC_CHARACTERS))
|| (0 == name_str.case_compare(DEFAULT_NAME_SORT) && 0 == value_str.case_compare(DEFAULT_VALUE_SORT))
|| (0 == name_str.case_compare(DEFAULT_NAME_COMP) && 0 == value_str.case_compare(DEFAULT_VALUE_COMP))
|| (0 == name_str.case_compare(DEFAULT_NAME_CURRENCY) && 0 == value_str.case_compare(DEFAULT_VALUE_CURRENCY))
|| (0 == name_str.case_compare(DEFAULT_NAME_ISO_CURRENCY) && 0 == value_str.case_compare(DEFAULT_VALUE_ISO_CURRENCY))
|| (0 == name_str.case_compare(DEFAULT_NAME_DUAL_CURRENCY) && 0 == value_str.case_compare(DEFAULT_VALUE_DUAL_CURRENCY))) {
bret = true;
}
}
}
return bret;
}
/*
* get default collation type from session for string type
* do not use this function for non-string type
* */
ObCollationType ObExprOperator::get_default_collation_type(
ObObjType type,
const ObBasicSessionInfo &session_info
)
{
ObCollationType collation_type = CS_TYPE_INVALID;
if (ob_is_string_or_lob_type(type)) {
if (lib::is_mysql_mode()) {
collation_type = static_cast<ObCollationType>(session_info.get_local_collation_connection());
} else {
if (ob_is_nstring(type)) {
//nvarchar2 nchar nclob
collation_type = session_info.get_nls_collation_nation();
} else {
//varchar2 char clob
collation_type = session_info.get_nls_collation();
}
}
}
return collation_type;
}
OB_SERIALIZE_MEMBER(ObExprOperator, row_dimension_, real_param_num_, result_type_, input_types_, id_, extra_serialize_);
int ObExprOperator::aggregate_collations(ObObjMeta &type,
const ObObjMeta *types,
int64_t param_num,
uint32_t flags,
const ObCollationType conn_coll_type)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num <= 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong",K(types), K(param_num), K(ret));
} else {
ObCollationType coll_type = types[0].get_collation_type();
ObCollationLevel coll_level = types[0].get_collation_level();
for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) {
ret = ObCharset::aggregate_collation(coll_level, coll_type,
types[i].get_collation_level(),
types[i].get_collation_type(),
coll_level, coll_type);
}
if (OB_SUCC(ret)) {
if (OB_UNLIKELY((flags & OB_COLL_DISALLOW_NONE) && CS_LEVEL_NONE == coll_level)) {
// @todo (zhuweng.yzf) correct error code is OB_CANT_AGGREGATE_NCOLLATIONS
ret = OB_CANT_AGGREGATE_2COLLATIONS;
}
}
if (OB_SUCC(ret)) {
/* If all arguments were numbers, reset to @@collation_connection */
if (OB_UNLIKELY((flags & OB_COLL_ALLOW_NUMERIC_CONV) && CS_LEVEL_NUMERIC == coll_level)) {
coll_type = conn_coll_type;
coll_level = CS_LEVEL_COERCIBLE;
// MySQL need charset converter here. We consider only two charset(binary
// and utf8mb4), so no conversion is actually needed
} else {}
if (OB_SUCC(ret)) {
type.set_collation_type(coll_type);
type.set_collation_level(coll_level);
} else {}
} else {}
if (OB_CANT_AGGREGATE_2COLLATIONS == ret) {
if (3 == param_num) {
ret = OB_CANT_AGGREGATE_3COLLATIONS;
} else if (3 < param_num) {
ret = OB_CANT_AGGREGATE_NCOLLATIONS;
}
}
}
return ret;
}
// We consider only two charset: binary and utf8mb4, so no conversion is actually needed
int ObExprOperator::aggregate_charsets_for_string_result(
ObObjMeta &type,
const ObObjMeta *types,
int64_t param_num,
const ObCollationType conn_coll_type)
{
uint32_t flags = OB_COLL_ALLOW_NUMERIC_CONV;
return aggregate_charsets(type, types, param_num, flags, conn_coll_type);
}
int ObExprOperator::aggregate_charsets_for_string_result(
ObExprResType &type,
const ObExprResType *types,
int64_t param_num,
const ObCollationType conn_coll_type)
{
uint32_t flags = OB_COLL_ALLOW_NUMERIC_CONV;
return aggregate_charsets(type, types, param_num, flags, conn_coll_type);
}
int ObExprOperator::aggregate_charsets_for_comparison(
ObObjMeta &type,
const ObObjMeta *types,
int64_t param_num,
const ObCollationType conn_coll_type)
{
uint32_t flags = OB_COLL_DISALLOW_NONE;
return aggregate_charsets(type, types, param_num, flags, conn_coll_type);
}
int ObExprOperator::aggregate_charsets_for_comparison(
ObExprResType &type,
const ObExprResType *types,
int64_t param_num,
const ObCollationType conn_coll_type)
{
uint32_t flags = OB_COLL_DISALLOW_NONE;
return aggregate_charsets(type.get_calc_meta(), types, param_num, flags, conn_coll_type);
}
int ObExprOperator::aggregate_charsets_for_string_result_with_comparison(
ObObjMeta &type,
const ObObjMeta *types,
int64_t param_num,
const ObCollationType conn_coll_type)
{
uint32_t flags = OB_COLL_DISALLOW_NONE | OB_COLL_ALLOW_NUMERIC_CONV;
return aggregate_charsets(type, types, param_num, flags, conn_coll_type);
}
int ObExprOperator::aggregate_charsets_for_string_result_with_comparison(
ObObjMeta &type,
const ObExprResType *types,
int64_t param_num,
const ObCollationType coll_type)
{
uint32_t flags = OB_COLL_DISALLOW_NONE | OB_COLL_ALLOW_NUMERIC_CONV;
return aggregate_charsets(type, types, param_num, flags, coll_type);
}
int ObExprOperator::aggregate_charsets(
ObObjMeta &type,
const ObObjMeta *types,
int64_t param_num,
uint32_t flags,
const ObCollationType conn_coll_type)
{
return aggregate_collations(type, types, param_num, flags, conn_coll_type);
}
int ObExprOperator::aggregate_charsets(
ObObjMeta &type,
const ObExprResType *types,
int64_t param_num,
uint32_t flags,
const ObCollationType conn_coll_type)
{
int ret = OB_SUCCESS;
CK(OB_NOT_NULL(types),
!OB_UNLIKELY(param_num < 1));
if (OB_SUCC(ret)) {
ObSEArray<ObObjMeta, 16> coll_types;
ObObjMeta coll;
for (int i = 0; OB_SUCC(ret) && i < param_num; ++i) {
coll.reset();
coll.set_collation_type(types[i].get_collation_type());
coll.set_collation_level(types[i].get_collation_level());
ret = coll_types.push_back(coll);
} // end for
OZ (aggregate_charsets(type,
&coll_types.at(0),
param_num,
flags,
conn_coll_type));
}
return ret;
}
/**
* @brief 表达式字符集推导: 综合考虑输入参数(params)的type和collation,得出result的type和collation
* @param result 表达式结果类型
* @param params 表达式参与推导的参数数组
* @param deduce_flag 某些表达式对推导有一些特殊配置
* @return
*/
int ObExprOperator::aggregate_string_type_and_charset_oracle(
const ObBasicSessionInfo &session,
const ObIArray<ObExprResType *> &params,
ObExprResType &result,
int64_t deduce_flag /*=0*/)
{
int ret = OB_SUCCESS;
bool has_clob_type = false;
bool has_character_type = false;
bool has_varying_len_string_type = false;
bool has_nation_string_type = false;
CK (params.count() > 0);
for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) {
const ObExprResType *param_meta = params.at(i);
CK (OB_NOT_NULL(param_meta));
if (OB_SUCC(ret)) {
if (param_meta->is_string_or_lob_locator_type()) { //当前可以区分null和空串
has_clob_type |= param_meta->is_clob();
has_clob_type |= param_meta->is_clob_locator();
has_character_type |= param_meta->is_character_type();
has_nation_string_type |= param_meta->is_nstring();
has_varying_len_string_type |= param_meta->is_varying_len_char_type();
} else {
//非string类型会转成varchar
has_varying_len_string_type = true;
}
}
}
/* 1. deduce type + charset
* 综合考虑每个param type得到result type
* 从session获取类型对应的collation得到result collation
* */
ObObjType result_type = ObMaxType;
ObCollationType result_charset = CS_TYPE_INVALID;
if (OB_SUCC(ret)) {
if (has_clob_type) {
if (has_nation_string_type) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "type nclob");
} else {
result_type = ObLongTextType;
result_charset = session.get_nls_collation();
}
} else if (has_character_type) {
if (has_nation_string_type) {
result_type = has_varying_len_string_type || (deduce_flag & PREFER_VAR_LEN_CHAR) ?
ObNVarchar2Type : ObNCharType;
result_charset = session.get_nls_collation_nation();
} else {
result_type = has_varying_len_string_type || (deduce_flag & PREFER_VAR_LEN_CHAR) ?
ObVarcharType : ObCharType;
result_charset = session.get_nls_collation();
}
} else { //blob and other types
result_type = ObVarcharType;
result_charset = session.get_nls_collation();
}
}
if (OB_SUCC(ret)) {
result.set_type_simple(result_type);
if (ob_is_large_text(result_type) || ob_is_json(result_type)) {
result.set_inrow();
}
result.set_collation_type(result_charset);
result.set_collation_level(CS_LEVEL_IMPLICIT);
}
/* 2. deduce 长度语义
* */
OZ (aggregate_length_semantics_oracle(session, params, result, deduce_flag));
LOG_DEBUG("aggregate string charset", K(result), K(params));
return ret;
}
int ObExprOperator::aggregate_length_semantics_oracle(
const ObBasicSessionInfo &session,
const ObIArray<ObExprResType *> &params,
ObExprResType &result,
int64_t deduce_flag /*=0*/)
{
int ret = OB_SUCCESS;
ObLengthSemantics result_ls = LS_INVALIED;
if (lib::is_oracle_mode()) {
if (result.is_nstring() || result.is_clob() || result.is_clob_locator()) {
result_ls = LS_CHAR;
} else if (deduce_flag & PREFER_NLS_LENGTH_SEMANTICS) {
result_ls = session.get_actual_nls_length_semantics();
} else {
bool is_all_the_same = true;
for (int64_t i = 0; is_all_the_same && i < params.count(); ++i) {
const ObExprResType *param_meta = params.at(i);
if (!param_meta->is_literal() && param_meta->is_string_or_lob_locator_type()) {
ObLengthSemantics curr_ls = param_meta->get_length_semantics();
if (LS_INVALIED == result_ls) {
result_ls = curr_ls;
} else {
is_all_the_same = (result_ls == curr_ls);
}
}
}
if (!is_all_the_same || LS_INVALIED == result_ls) {
result_ls = session.get_actual_nls_length_semantics();
}
}
if (OB_SUCC(ret)) {
result.set_length_semantics(result_ls);
}
}
return ret;
}
/**
* @brief 表达式字符集推导: 根据表达式结果(result)的type和collation,给参数的calc type赋值
* @param result 表达式结果类型
* @param params 表达式需要参与推导的参数数组
* @param calc_ls 当参数的长度语义需要和结果不同时,可以显示指定
* @return
*/
int ObExprOperator::deduce_string_param_calc_type_and_charset(
const ObBasicSessionInfo &session,
const ObExprResType &result,
ObIArray<ObExprResType *> &params,
const ObLengthSemantics calc_ls /*=LS_INVALIED*/)
{
UNUSED(session);
int ret = OB_SUCCESS;
ObLengthSemantics length_semantic = result.get_length_semantics();
if (result.is_varchar_or_char() && (LS_BYTE == calc_ls || LS_CHAR == calc_ls)) {
length_semantic = calc_ls;
}
for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) {
ObExprResType *param_meta = params.at(i);
ObLength length;
CK (OB_NOT_NULL(param_meta));
OX (param_meta->set_calc_meta(result));
OX (param_meta->set_calc_length_semantics(length_semantic));
OZ(ObExprResultTypeUtil::deduce_max_string_length_oracle( session.get_dtc_params(),
*param_meta, result, length, calc_ls));
OX (param_meta->set_calc_length(length));
}
return ret;
}
int ObExprOperator::is_same_kind_type_for_case(const ObExprResType &type1, const ObExprResType &type2, bool &match)
{
int ret = OB_SUCCESS;
match = false;
if (OB_UNLIKELY(type1.get_type() >= ObMaxType || type2.get_type() >= ObMaxType)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("the wrong type", K(type1), K(type2), K(ret));
} else {
if (ob_is_null(type1.get_type()) || ob_is_null(type2.get_type())) {
match = true;
} else if (ob_is_varchar_char_type(type1.get_type(), type1.get_collation_type())) {
match = ob_is_varchar_char_type(type2.get_type(), type2.get_collation_type());
} else if (ob_is_numeric_type(type1.get_type())) {
match = ob_is_numeric_type(type2.get_type());
} else if (ob_is_datetime_tc(type1.get_type()) || ob_is_otimestampe_tc(type1.get_type())) {
match = ob_is_datetime_tc(type2.get_type()) || ob_is_otimestampe_tc(type2.get_type());
} else if (ob_is_blob(type1.get_type(), type1.get_collation_type())) {
match = ob_is_blob(type2.get_type(), type2.get_collation_type());
} else if (ob_is_text(type1.get_type(), type1.get_collation_type())) {
match = ob_is_text(type2.get_type(), type2.get_collation_type());
} else if (ob_is_varbinary_type(type1.get_type(), type1.get_collation_type())) {
match = ob_is_varbinary_type(type2.get_type(), type2.get_collation_type());
} else if (ob_is_raw(type1.get_type())) {
match = ob_is_raw(type2.get_type());
} else if (ob_is_interval_ym(type1.get_type())) {
match = ob_is_interval_ym(type2.get_type());
} else if (ob_is_interval_ds(type1.get_type())) {
match = ob_is_interval_ds(type2.get_type());
} else if (ob_is_nstring_type(type1.get_type())) {
match = ob_is_nstring_type(type2.get_type());
} else if (ob_is_urowid(type1.get_type())) {
match = ob_is_urowid(type2.get_type());
} else if (ob_is_blob_locator(type1.get_type(), type1.get_collation_type())) {
match = ob_is_blob_locator(type2.get_type(), type2.get_collation_type());
} else if (ob_is_clob_locator(type1.get_type(), type1.get_collation_type())) {
match = ob_is_clob_locator(type2.get_type(), type2.get_collation_type());
} else if (ob_is_extend(type1.get_type()) && ob_is_extend(type2.get_type())) {
match = (type1.get_accuracy() == type2.get_accuracy());
} else if (ob_is_json(type1.get_type())) {
match = ob_is_json(type2.get_type());
}
}
return ret;
}
// coaesce expr, case when expr
int ObExprOperator::aggregate_result_type_for_case(
ObExprResType &type,
const ObExprResType *types,
int64_t param_num,
const ObCollationType conn_coll_type,
bool is_oracle_mode,
const ObLengthSemantics default_length_semantics,
const ObSQLSessionInfo *session,
bool need_merge_type,
bool skip_null,
bool is_called_in_sql)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1) || OB_ISNULL(session)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else if (1 == param_num && ob_is_enumset_tc(types[0].get_type())) {
} else if (is_oracle_mode) {
bool match = false;
int64_t nth = OB_INVALID_ID;
for (int64_t i = 0; OB_SUCC(ret) && OB_INVALID_ID == nth && i < param_num; ++i) {
if (!ob_is_null(types[i].get_type())) {
nth = i;
}
}
nth = OB_INVALID_ID == nth ? 0 : nth;
const ObExprResType &res_type = types[nth];
if (need_merge_type && lib::is_oracle_mode() && ObTinyIntType == types[0].get_type()) {
ret = OB_ERR_CALL_WRONG_ARG;
LOG_WARN("PLS-00306: wrong number or types of arguments in call", K(ret));
}
for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) {
if (need_merge_type && lib::is_oracle_mode() && ObTinyIntType == types[i].get_type()) {
ret = OB_ERR_CALL_WRONG_ARG;
LOG_WARN("PLS-00306: wrong number or types of arguments in call", K(ret));
} else if (OB_FAIL(ObExprOperator::is_same_kind_type_for_case(res_type,
types[i], match))) {
LOG_WARN("fail to judge same type", K(i), K(res_type), K(types[i]), K(ret));
} else if (!match) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_WARN("fail to judge same type", K(i), K(res_type), K(types[i]), K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(aggregate_result_type_for_merge(type, types, param_num, conn_coll_type,
is_oracle_mode, default_length_semantics, session, 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);
}
}
return ret;
}
int ObExprOperator::aggregate_result_type_for_merge(
ObExprResType &type,
const ObExprResType *types,
int64_t param_num,
const ObCollationType conn_coll_type,
bool is_oracle_mode,
const ObLengthSemantics default_length_semantics,
const ObSQLSessionInfo *session,
bool need_merge_type,
bool skip_null,
bool is_called_in_sql)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1) || OB_ISNULL(session)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else if (1 == param_num && ob_is_enumset_tc(types[0].get_type())) {
//this is for case when clause like case when 1 then c1 end;
type.set_type(ObVarcharType);
type.set_collation_level(common::CS_LEVEL_IMPLICIT);
type.set_collation_type(session->get_local_collation_connection());
} else {
ObObjType res_type = types[0].get_type();
for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) {
if (OB_FAIL(ObExprResultTypeUtil::get_merge_result_type(res_type,
res_type,
types[i].get_type()))) {
// warn
} else if (OB_UNLIKELY(ObMaxType == res_type)) {
ret = OB_INVALID_ARGUMENT; // not compatible input
LOG_WARN("invalid argument. wrong type for merge", K(i), K(types[i].get_type()), K(ret));
}
}
if (OB_SUCC(ret)) {
type.set_type(res_type);
if (ob_is_numeric_type(res_type)) {
ret = aggregate_numeric_accuracy_for_merge(type, types, param_num, is_oracle_mode);
} 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, conn_coll_type))) {
} else if (OB_FAIL(aggregate_max_length_for_string_result(type, types, param_num,
is_oracle_mode, default_length_semantics, need_merge_type, skip_null,
is_called_in_sql))) {
} else {/*do nothing*/}
} else if (ob_is_raw(res_type)) {
type.set_collation_type(CS_TYPE_BINARY);
type.set_collation_level(CS_LEVEL_NUMERIC);
} else if (ob_is_interval_tc(res_type)) {
ret = aggregate_accuracy_for_merge(type, types, param_num);
} else if (ob_is_extend(res_type)) {
OZ (aggregate_extend_accuracy_for_merge(type, types, param_num));
} else if (ob_is_json(res_type)) {
type.set_collation_type(CS_TYPE_UTF8MB4_BIN);
type.set_collation_level(CS_LEVEL_IMPLICIT);
}
}
LOG_DEBUG("merged type is", K(type), K(is_oracle_mode));
}
return ret;
}
int ObExprOperator::aggregate_max_length_for_string_result(ObExprResType &type,
const ObExprResType *types,
int64_t param_num,
bool is_oracle_mode,
const ObLengthSemantics default_length_semantics,
bool need_merge_type,
bool skip_null,
bool is_called_in_sql)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else {
ObLength max_length = -1;
ObLength max_length_char = -1;
ObLength length = -1;
ObLengthSemantics length_semantics = -1;
int64_t byte_length_count = 0;
int64_t char_length_count = 0;
bool len_in_byte = false;
int64_t mbmaxlen = 1;
if (OB_FAIL(common::ObCharset::get_mbmaxlen_by_coll(CS_TYPE_UTF8MB4_GENERAL_CI, mbmaxlen))) {
LOG_WARN("fail to get mbmaxlen", K(ret));
} else if (OB_FAIL(ObCharset::get_aggregate_len_unit(type.get_collation_type(), len_in_byte))) {
LOG_WARN("get aggregate len unit failed", K(ret), K(type));
} else if (len_in_byte) {
//binary
for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) {
if (ob_is_integer_type(types[i].get_type())) {
length = MAX(ObAccuracy::DDL_DEFAULT_ACCURACY[types[i].get_type()].precision_,
types[i].get_precision());
} else {
if (OB_FAIL(types[i].get_length_for_meta_in_bytes(length))) {
LOG_WARN("get length failed", K(ret), K(types[i]));
}
}
/* Oracle compatible: if prejudged result type is char and args' length are different, change result type to varchar */
LOG_DEBUG("cur len", K(length), K(max_length), K(types[i]));
if (is_oracle_mode && need_merge_type
&& ((ObCharType == type.get_type() && ObCharType == types[i].get_type())
|| (ob_is_nchar(type.get_type()) && ob_is_nchar(types[i].get_type())))
&& (max_length != -1) && (length != max_length)) {
LOG_DEBUG("Merge type from Char to Varchar ", K(length), K(max_length), K(types[i]));
type.set_type(ob_is_nchar(type.get_type()) ? ObNVarchar2Type : ObVarcharType);
}
/*no need to if(OB_SUCCE(ret)) here*/
if (length > max_length) {
if (types[i].is_null() && skip_null) {
//skip
} else {
max_length = length;
}
}
}//end for
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) {
if (ob_is_integer_type(types[i].get_type())) {
length = MAX(ObAccuracy::DDL_DEFAULT_ACCURACY[types[i].get_type()].precision_,
types[i].get_precision());
length_semantics = -1;
} else {
length = types[i].get_length();
length_semantics = types[i].get_length_semantics();
if (LS_BYTE == length_semantics) {
byte_length_count++;
} else if (LS_CHAR == length_semantics) {
char_length_count++;
if (length > max_length_char) {
max_length_char = length;
}
}
}
/* Oracle compatible: if prejudged result type is char and args' length are different, change result type to varchar */
LOG_DEBUG("cur len", K(length), K(max_length), K(max_length_char), K(length_semantics), K(types[i]), K(type));
if (is_oracle_mode
&& need_merge_type
&& ((ObCharType == type.get_type() && ObCharType == types[i].get_type())
|| (ob_is_nchar(type.get_type()) && ob_is_nchar(types[i].get_type())))
&& (max_length != -1)
&& (length != max_length || (byte_length_count > 0 && char_length_count > 0))) {
LOG_DEBUG("Merge type from Char to Varchar ", K(length), K(max_length), K(length_semantics), K(types[i]));
type.set_type(ob_is_nchar(type.get_type()) ? ObNVarchar2Type : ObVarcharType);
}
if (length > max_length) {
if (types[i].is_null() && skip_null) {
//skip
} else {
max_length = length;
}
}
}//end for
}
//set length
if (OB_SUCC(ret) && max_length < 0) {
if (skip_null) {
max_length = 0;
} else {
if (!is_called_in_sql && lib::is_oracle_mode()) {
if (type.is_char() || type.is_nchar()) {
type.set_length(OB_MAX_ORACLE_PL_CHAR_LENGTH_BYTE);
} else if (type.is_nvarchar2() || type.is_varchar()) {
type.set_length(OB_MAX_ORACLE_VARCHAR_LENGTH);
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected max length.", K(ret), K(max_length), K(param_num), K(len_in_byte));
}
}
}
if (OB_SUCC(ret)) {
if (is_oracle_mode && type.is_character_type()) {
if (type.is_nstring()) {
type.set_length_semantics(LS_CHAR);
} else {
if (byte_length_count > 0 && 0 == char_length_count) {
type.set_length_semantics(LS_BYTE);
} else if (char_length_count > 0 && 0 == byte_length_count) {
type.set_length_semantics(LS_CHAR);
} else {
type.set_length_semantics(default_length_semantics);
}
}
if (LS_CHAR == type.get_length_semantics()) {
type.set_length(std::max(max_length_char, max_length));
} else {
type.set_length(std::max(static_cast<ObLength>(max_length_char * mbmaxlen), max_length));
}
} else {
type.set_length(max_length);
}
}
}
return ret;
}
int ObExprOperator::aggregate_accuracy_for_merge(ObExprResType &type,
const ObExprResType *types,
int64_t param_num)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else {
ObScale scale = -1;
for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) {
if (types[i].get_scale() > scale) {
scale = types[i].get_scale();
}
}
if (OB_UNLIKELY(scale < 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected scale.", K(ret), K(scale));
} else {
type.set_scale(scale);
}
}
return ret;
}
int ObExprOperator::aggregate_temporal_accuracy_for_merge(ObExprResType &type,
const ObExprResType *types,
int64_t param_num)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else {
ObScale scale = -1;
for (int64_t i = 0; OB_SUCC(ret) && i < param_num; ++i) {
if ((ob_is_temporal_type(types[i].get_type()) || ob_is_otimestamp_type(types[i].get_type()))
&& types[i].get_scale() > scale) {
scale = types[i].get_scale();
}
}
if (OB_UNLIKELY(scale < 0)) {
type.set_scale(ObAccuracy::MAX_ACCURACY2[is_oracle_mode()][type.get_type()].get_scale());
} else {
type.set_scale(scale);
}
}
return ret;
}
int ObExprOperator::aggregate_numeric_accuracy_for_merge(ObExprResType &type,
const ObExprResType *types,
int64_t param_num,
bool is_oracle_mode)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else if (is_oracle_mode) {
type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET);
type.set_precision(PRECISION_UNKNOWN_YET);
} else {
ObPrecision precision = 0;
ObScale scale = 0;
int16_t max_integer_digits = -1;
int16_t max_decimal_digits = -1;
bool has_real_type = false;
for (int64_t i = 0; i < param_num && OB_SUCC(ret); ++i) {
precision = PRECISION_UNKNOWN_YET;
scale = SCALE_UNKNOWN_YET;
if (OB_UNLIKELY(types[i].get_type() < ObNullType
|| types[i].get_type() >= ObMaxType)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected error. wrong type", K(ret), K(types[i]));
} else if (ob_is_real_type(types[i].get_type())) {
/*https://k3.alibaba-inc.com/issue/8306249
create table sb(a float);
create table sc(c year);
insert sb values (1.5);
insert sc values(1923);
a union c will result to 1.5 and 1923
*/
has_real_type = true;
} else {
/*
create table sb(a int(3));//3 ? display width ? precision? length?
create table sc(c decimal(5,3));
insert sb values (12345);
insert sc values(123.33);
a union c will result to 12345 and 123.33
*/
if (ob_is_integer_type(types[i].get_type())) {
precision = MAX(ObAccuracy::DDL_DEFAULT_ACCURACY2[is_oracle_mode][types[i].get_type()].precision_,
types[i].get_precision());
scale = 0;
} else if (ob_is_number_tc(types[i].get_type())
|| ob_is_temporal_type(types[i].get_type())
|| ob_is_bit_tc(types[i].get_type())) {
precision = types[i].get_precision();
scale = types[i].get_scale();
} else {
//string type. precision and scale means nothing to string types
//just let it go
}
if (precision >= 0 && precision - scale > max_integer_digits) {
max_integer_digits = static_cast<int16_t>(precision - scale);
}
if (scale >= 0 && scale > max_decimal_digits) {
max_decimal_digits = scale;
}
}
}
if (OB_FAIL(ret)) {
} else if (ob_is_real_type(type.get_type()) && has_real_type) {
type.set_precision(PRECISION_UNKNOWN_YET);
type.set_scale(SCALE_UNKNOWN_YET);
} else {
if (max_integer_digits + max_decimal_digits >= 0) {
precision = static_cast<ObPrecision>(max_integer_digits + max_decimal_digits);
type.set_precision(MIN(precision, ObAccuracy::MAX_ACCURACY2[is_oracle_mode][type.get_type()].precision_));
}
if (max_decimal_digits >= 0) {
type.set_scale(MIN(max_decimal_digits, ObAccuracy::MAX_ACCURACY2[is_oracle_mode][type.get_type()].scale_));
}
}
}
return ret;
}
int ObExprOperator::aggregate_extend_accuracy_for_merge(ObExprResType &type,
const ObExprResType *types,
int64_t param_num)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)
|| OB_UNLIKELY(!ob_is_extend(type.get_type()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else {
bool find_extend = false;
for (int64_t i = 0; !find_extend && i < param_num && OB_SUCC(ret); ++i) {
if (ob_is_extend(types[i].get_type())) {
find_extend = true;
type.set_accuracy(types[i].get_accuracy().get_accuracy());
}
}
}
return ret;
}
int ObExprDFMConvertCtx::parse_format(const ObString &format_str,
const ObObjType target_type,
bool check_format_semantic,
ObIAllocator &allocator)
{
int ret = OB_SUCCESS;
ObSEArray<ObDFMElem, ObDFMUtil::COMMON_ELEMENT_NUMBER> dfm_elems;
ObFixedBitSet<OB_DEFAULT_BITSET_SIZE_FOR_DFM> elem_flags;
//parse format
ObDTMode mode = DT_TYPE_DATETIME;
if (ob_is_otimestamp_type(target_type)) {
mode |= DT_TYPE_ORACLE;
}
if (ob_is_timestamp_tz(target_type)) {
mode |= DT_TYPE_TIMEZONE;
}
OZ (ObDFMUtil::parse_datetime_format_string(format_str, dfm_elems));
if (check_format_semantic) {
OZ (ObDFMUtil::check_semantic(dfm_elems, elem_flags, mode));
}
OX (dfm_elems_.set_allocator(&allocator));
OZ (dfm_elems_.assign(dfm_elems));
OZ (elem_flags_.add_members(elem_flags));
return ret;
}
ObObjType ObExprOperator::enumset_calc_types_[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*/
};
////////////////////////////////////////////////////////////////
int ObArithExprOperator::assign(const ObExprOperator &other)
{
int ret = OB_SUCCESS;
const ObArithExprOperator *tmp_other = dynamic_cast<const ObArithExprOperator *>(&other);
if (OB_UNLIKELY(NULL == tmp_other)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument. wrong type for other", K(ret), K(other));
} else if (this != tmp_other) {
if (OB_FAIL(ObExprOperator::assign(other))) {
LOG_WARN("copy in Base class ObExprOperator failed", K(ret));
} else {
this->result_type_func_ = tmp_other->result_type_func_;
this->calc_type_func_ = tmp_other->calc_type_func_;
}
}
return ret;
}
int ObArithExprOperator::calc_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
if (OB_ISNULL(result_type_func_) || OB_ISNULL(calc_type_func_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("result_type_func_ or calc_type_func_is null",K(ret));
} else {
ObObjType calc_type = ObMaxType;
ObObjType calc_ob1_type = ObMaxType;
ObObjType calc_ob2_type = ObMaxType;
if (OB_UNLIKELY(NOT_ROW_DIMENSION != row_dimension_)) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
} else if (OB_FAIL(result_type_func_(type, type1, type2))) {
LOG_WARN("fail to result_type_func_",K(ret));
} else if (OB_UNLIKELY(ObMaxType == type.get_type())) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
} else if (OB_FAIL(calc_type_func_(calc_type,
calc_ob1_type,
calc_ob2_type,
type1.get_type(),
type2.get_type()))) {
LOG_WARN("fail to calc_type_func_",K(ret));
} else {
type.set_calc_type(calc_type);
type1.set_calc_type(get_calc_cast_type(type1.get_type(), calc_ob1_type));
type2.set_calc_type(get_calc_cast_type(type2.get_type(), calc_ob2_type));
ObExprOperator::calc_result_flag2(type, type1, type2);
}
LOG_DEBUG("arithmatic result type", K(type), K(type1), K(type2), K(calc_type),
K(calc_ob1_type), K(calc_ob2_type), K(ret));
}
return ret;
}
int ObArithExprOperator::calc_result2(ObObj &result,
const ObObj &left,
const ObObj &right,
ObExprCtx &expr_ctx) const
{
return calc_(result,
left,
right,
expr_ctx,
result_type_.get_calc_scale(),
result_type_.get_calc_type(),
arith_funcs_);
}
int ObArithExprOperator::calc(ObObj &result,
const ObObj &left,
const ObObj &right,
ObIAllocator *allocator,
ObScale scale,
ObCalcTypeFunc calc_type_func,
const ObArithFunc *arith_funcs)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(calc_type_func) || OB_ISNULL(allocator) || OB_ISNULL(arith_funcs)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("the pointer is null", K(calc_type_func), K(allocator), K(arith_funcs),K(ret));
} else {
ObObjType calc_type = ObMaxType;
ObObjType calc_ob1_type = ObMaxType;
ObObjType calc_ob2_type = ObMaxType;
if (OB_FAIL(calc_type_func(calc_type,
calc_ob1_type,
calc_ob2_type,
left.get_type(),
right.get_type()))) {
} else {
ObExprCtx expr_ctx(NULL, NULL, NULL, allocator);
ret = calc_(result, left, right, expr_ctx, scale, calc_type, arith_funcs);
}
}
return ret;
}
int ObArithExprOperator::calc(ObObj &result,
const ObObj &left,
const ObObj &right,
ObExprCtx &expr_ctx,
ObScale calc_scale,
ObCalcTypeFunc calc_type_func,
const ObArithFunc *arith_funcs)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(calc_type_func) || OB_ISNULL(arith_funcs)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("calc_type_func is null",K(ret));
} else {
ObObjType calc_type = ObMaxType;
ObObjType calc_ob1_type = ObMaxType;
ObObjType calc_ob2_type = ObMaxType;
if (OB_FAIL(calc_type_func(calc_type,
calc_ob1_type,
calc_ob2_type,
left.get_type(),
right.get_type()))) {
} else {
ret = calc_(result, left, right, expr_ctx, calc_scale, calc_type, arith_funcs);
}
}
return ret;
}
int ObArithExprOperator::calc_(ObObj &result,
const ObObj &left,
const ObObj &right,
ObExprCtx &expr_ctx,
ObScale calc_scale,
ObObjType calc_type,
const ObArithFunc *arith_funcs)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(arith_funcs) || OB_ISNULL(expr_ctx.calc_buf_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("the pointer is null", K(arith_funcs), K(expr_ctx.calc_buf_), K(ret));
} else if (OB_UNLIKELY(ObNullType == calc_type || ObMaxType == calc_type)) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_WARN("result type is invalid", K(ret), K(calc_type));
}
if (OB_SUCC(ret) && (OB_UNLIKELY(ObNullType == left.get_type() || ObNullType == right.get_type()))) {
result.set_null();
} else if (OB_SUCC(ret)) {
const ObObj *res_left = &left;
const ObObj *res_right = &right;
ObObj tmp_left_obj;
ObObj tmp_right_obj;
if (left.get_type() != calc_type || right.get_type() != calc_type) {
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NO_CAST_INT_UINT);
if (is_datetime_add_minus_calc(calc_type, arith_funcs)) {
if (OB_FAIL(ObObjCaster::to_datetime(calc_type, cast_ctx,
left, tmp_left_obj, res_left))) {
LOG_WARN("cast failed.", K(ret), K(left), K(calc_type));
} else if (OB_FAIL(ObObjCaster::to_datetime(calc_type, cast_ctx,
right, tmp_right_obj, res_right))) {
LOG_WARN("cast failed.", K(ret), K(right), K(calc_type));
}
} else if (OB_FAIL(ObObjCaster::to_type(calc_type,
cast_ctx,
left,
tmp_left_obj,
res_left))) {
LOG_WARN("cast failed.", K(ret), K(left), K(calc_type));
} else if (OB_FAIL(ObObjCaster::to_type(calc_type,
cast_ctx,
right,
tmp_right_obj,
res_right))) {
LOG_WARN("cast failed.", K(ret), K(right), K(calc_type));
}
}
//ok, let's calc it.
if (OB_SUCC(ret)) {
ObArithFunc arith_func = arith_funcs[res_left->get_type_class()];
LOG_DEBUG("begin calc", K(left), KPC(res_left), K(right), KPC(res_right), K(calc_scale),
K(calc_type), K(lbt()));
if (OB_ISNULL(arith_func)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("arith_func is null",K(ret));
} else {
ret = arith_func(result,
*res_left,
*res_right,
expr_ctx.calc_buf_,
calc_scale);
if (OB_ERR_UNEXPECTED == ret) {
ob_abort();
}
}
}
// }
}
return ret;
}
bool ObArithExprOperator::is_datetime_add_minus_calc(const common::ObObjType calc_type,
const ObArithFunc *arith_funcs)
{
return (NULL != arith_funcs
&& (ObExprAdd::add_datetime == arith_funcs[ob_obj_type_class(calc_type)]
|| ObExprMinus::minus_datetime == arith_funcs[ob_obj_type_class(calc_type)]));
}
int ObRelationalExprOperator::deserialize(const char *buf, const int64_t data_len, int64_t &pos)
{
int ret = OB_SUCCESS;
cmp_op_func2_ = NULL;
ret = ObExprOperator::deserialize(buf, data_len, pos);
if (OB_SUCC(ret) && (IS_COMMON_COMPARISON_OP(type_) || T_FUN_SYS_STRCMP == type_)
&& ObExprOperator::NOT_ROW_DIMENSION == row_dimension_
&& real_param_num_ == 2) {
if (input_types_.count() != 2) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected error. invalid input types",
K(ret),
K(type_),
K(real_param_num_),
K(input_types_.count()));
} else {
ObObjType left_operand_type = input_types_.at(0).get_calc_type();
ObObjType right_operand_type = input_types_.at(1).get_calc_type();
if (OB_FAIL(set_cmp_func(left_operand_type, right_operand_type))) {
LOG_WARN("set cmp func failed", K(ret), K(left_operand_type), K(right_operand_type), K(type_));
cmp_op_func2_ = NULL;//defensive code
}
}
}
return ret;
}
int ObRelationalExprOperator::compare(ObObj &result,
const ObObj &obj1,
const ObObj &obj2,
const ObCompareCtx &cmp_ctx,
ObCastCtx &cast_ctx,
ObCmpOp cmp_op)
{
int ret = OB_SUCCESS;
bool need_cast = false;
if (OB_FAIL(compare_nocast(result, obj1, obj2, cmp_ctx, cmp_op, need_cast))) {
LOG_WARN("failed to compare objects", K(obj1), K(obj2));
} else if (need_cast) {
if (OB_FAIL(compare_cast(result, obj1, obj2, cmp_ctx, cast_ctx, cmp_op))) {
LOG_WARN("failed to compare objects", K(obj1), K(obj2));
}
}
return ret;
}
int ObRelationalExprOperator::compare_cast(ObObj &result,
const ObObj &obj1,
const ObObj &obj2,
const ObCompareCtx &cmp_ctx,
ObCastCtx &cast_ctx,
ObCmpOp cmp_op)
{
int ret = OB_SUCCESS;
ObObj buf_obj1;
ObObj buf_obj2;
const ObObj *res_obj1 = NULL;
const ObObj *res_obj2 = NULL;
bool need_cast = false;
cast_ctx.dest_collation_ = cmp_ctx.cmp_cs_type_;
if (OB_FAIL(ObObjCaster::to_type(cmp_ctx.cmp_type_, cast_ctx, obj1, buf_obj1, res_obj1))) {
LOG_WARN("failed to cast obj", K(ret), K(cmp_ctx.cmp_type_), K(obj1));
} else if (OB_FAIL(ObObjCaster::to_type(cmp_ctx.cmp_type_, cast_ctx, obj2, buf_obj2, res_obj2))) {
LOG_WARN("failed to cast obj", K(ret), K(cmp_ctx.cmp_type_), K(obj2));
} else if (OB_ISNULL(res_obj1) || OB_ISNULL(res_obj2)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("res_obj1 or res_obj2 is null");
} else if (OB_FAIL(ObObjCmpFuncs::compare(result, *res_obj1, *res_obj2, cmp_ctx, cmp_op, need_cast))) {
LOG_WARN("failed to compare objects", K(ret), K(*res_obj1), K(*res_obj2), K(cmp_op));
} else if (need_cast) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to compare objects", K(ret), K(*res_obj1), K(*res_obj2), K(cmp_op));
}
return ret;
}
int ObRelationalExprOperator::compare_nullsafe(int64_t &result,
const ObObj &obj1,
const ObObj &obj2,
ObCastCtx &cast_ctx,
ObObjType cmp_type,
ObCollationType cmp_cs_type)
{
int ret = OB_SUCCESS;
ObObj res_obj;
int64_t tz_offset = 0;
if (OB_FAIL(get_tz_offset(cast_ctx.dtc_params_.tz_info_, tz_offset))) {
LOG_WARN("get tz_offset failed", K(ret), K(cast_ctx.dtc_params_.tz_info_), K(tz_offset));
} else {
ObCompareCtx cmp_ctx(cmp_type,
cmp_cs_type,
true,
tz_offset,
default_null_pos());
if (OB_FAIL(compare(res_obj, obj1, obj2, cmp_ctx, cast_ctx, CO_CMP))) {
} else {
result = res_obj.get_int();
}
}
return ret;
}
bool ObRelationalExprOperator::can_cmp_without_cast(ObExprResType type1,
ObExprResType type2,
ObCmpOp cmp_op,
const ObSQLSessionInfo &session)
{
bool need_no_cast = false;
UNUSED(session);
//特殊处理显示调用compare(例如:c1 > c2),此时enum/set均应该转换成string处理
//内部比较(order by),enum/set不需要转换。
if (ob_is_enum_or_set_type(type1.get_type())
&& ob_is_enum_or_set_type(type2.get_type())) {
need_no_cast = false;
} else {
if (ObDatumFuncs::is_string_type(type1.get_type())
&& ObDatumFuncs::is_string_type(type2.get_type())) {
need_no_cast = (ObCharset::charset_type_by_coll(type1.get_collation_type())
== ObCharset::charset_type_by_coll(type2.get_collation_type()))
//For cmp between padding type(char/nchar) and no-padding type(varchar/nvarchar)
//we used to treat both as no-padding type without cast, but if it is equal cond in a hash join op
//we will got different hash value from (char : 'a') and (varchar : 'a ') and a empty result set
//which is not cpmpat with oracle. So we check if left && right both need/no need calc end space.
//If left is same as right, we can process equal cond without cast,
//otherwise we have to cast one to another
&& (common::is_calc_with_end_space(type1.get_type(), type1.get_type(),
lib::is_oracle_mode(),
type1.get_collation_type(),
type1.get_collation_type())
== common::is_calc_with_end_space(type2.get_type(), type2.get_type(),
lib::is_oracle_mode(),
type2.get_collation_type(),
type2.get_collation_type()));
} else {
auto func_ptr = ObExprCmpFuncsHelper::get_eval_expr_cmp_func(type1.get_type(),
type2.get_type(),
cmp_op,
lib::is_oracle_mode(),
CS_TYPE_BINARY);
need_no_cast = (func_ptr != nullptr);
}
}
return need_no_cast;
}
/*
* Note that, the original motivation of this function is that,
*
* Provided that we have a = b and b = c in which a , b and c
* are of metainfo meta1, meta2, meta3, respectively
*
* So, can we deduce that a = c holds actually?
*
* this func tells you this via result when and only when the ret is OB_SUCCESS
*/
int ObRelationalExprOperator::is_equivalent(const ObObjMeta &meta1,
const ObObjMeta &meta2,
const ObObjMeta &meta3,
bool &result)
{
int ret = OB_SUCCESS;
result = false;
ObObjMeta equal_meta12;
ObObjMeta equal_meta23;
ObObjMeta equal_meta13;
if (OB_FAIL(get_equal_meta(equal_meta12, meta1, meta2))) {
LOG_WARN("get equal meta failed", K(ret), K(meta1), K(meta2));
} else if (OB_FAIL(get_equal_meta(equal_meta13, meta1, meta3))) {
LOG_WARN("get equal meta failed", K(ret), K(meta1), K(meta3));
} else if (OB_FAIL(get_equal_meta(equal_meta23, meta2, meta3))) {
LOG_WARN("get equal meta failed", K(ret), K(meta2), K(meta3));
} else if (OB_UNLIKELY(equal_meta12.get_type() == ObMaxType
|| equal_meta13.get_type() == ObMaxType /* no need to check ObNullType here*/
|| equal_meta23.get_type() == ObMaxType)) {
/*result = false;*/
} else if (equal_meta12.get_type() == equal_meta13.get_type()
&& equal_meta13.get_type() == equal_meta23.get_type()) {
if (OB_UNLIKELY(ob_is_string_or_lob_type(equal_meta12.get_type()))) {
//all are string type
result = equal_meta12.get_collation_type() == equal_meta13.get_collation_type()
&& equal_meta13.get_collation_type() == equal_meta23.get_collation_type();
} else {
result = true;
}
}
return ret;
}
int ObRelationalExprOperator::get_equal_meta(ObObjMeta &meta,
const ObObjMeta &meta1,
const ObObjMeta &meta2)
{
int ret = OB_SUCCESS;
ObObjType type = ObMaxType;
if (OB_FAIL(ObExprResultTypeUtil::get_relational_equal_type(type,
meta1.get_type(),
meta2.get_type()))) {
LOG_WARN("get equal type failed", K(ret), K(meta1), K(meta2));
} else if (ob_is_string_or_lob_type(type)) {
ObObjMeta coll_types[2] = {meta1, meta2};
ret = aggregate_charsets_for_comparison(meta, coll_types, 2, CS_TYPE_INVALID);
}
if (OB_SUCC(ret)) {
meta.set_type(type);
}
return ret;
}
// MySQL使用item_cmp_type来计算要比较的值需要转换成什么类型之后再比较
// Note: 比较用的类型,不是结果类型. compare的结果类型是LongLong
int ObExprOperator::calc_cmp_type2(ObExprResType &type,
const ObExprResType &type1,
const ObExprResType &type2,
const ObCollationType coll_type) const
{
int ret = OB_SUCCESS;
ObObjType cmp_type = ObMaxType;
// todo(jiuren): we can add such code after plan cache add same optimization.
// if (is_int_cmp_const_str(&type1, &type2, cmp_type)) {
// } else
if (is_oracle_mode() && (type1.is_blob() || type2.is_blob()
|| type1.is_blob_locator() || type2.is_blob_locator())
&& type_ != T_OP_IS && type_ != T_OP_IS_NOT) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()), ob_obj_type_str(type2.get_type()));
} else if (OB_FAIL(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type,
type1.get_type(),
type2.get_type()))) {
LOG_WARN("fail to get cmp_type",K(ret));
} else if (OB_UNLIKELY(ObMaxType == cmp_type)) {
ret = OB_INVALID_ARGUMENT;
} else if (ObURowIDType == cmp_type) {
// 如果比较是urwoid类型,只支持<urwoid, urowid>,<string, urwoid>, <urowid, string>,
// <NULL, urowid>, <urowid, NULL>
// 在这里就直接报错,不往下走了
if (OB_UNLIKELY(ObStringTC != type1.get_type_class() &&
ObRowIDTC != type1.get_type_class() &&
ObNullTC != type1.get_type_class())
|| OB_UNLIKELY(ObStringTC != type2.get_type_class() &&
ObRowIDTC != type2.get_type_class() &&
ObNullTC != type2.get_type_class())) {
ret = OB_INVALID_ROWID;
LOG_WARN("not supported compare type", K(ret), K(type1), K(type2));
LOG_USER_ERROR(OB_INVALID_ROWID);
}
}
if (OB_SUCC(ret)) {
type.set_calc_type(cmp_type);
// collation
if (ob_is_string_or_lob_type(cmp_type)) {
ObObjMeta coll_types[2];
coll_types[0].set_collation(type1);
coll_types[1].set_collation(type2);
ret = aggregate_charsets_for_comparison(type.get_calc_meta(), coll_types, 2, coll_type);
if (OB_FAIL(ret)) {
LOG_WARN("aggregate charset failed", K(type1), K(type2), K(type.get_calc_meta()));
}
} else if (ObRawType == cmp_type) {
type.get_calc_meta().set_collation_type(CS_TYPE_BINARY);
}
LOG_DEBUG("calc cmp type", K(type1), K(type2), K(type.get_calc_meta()));
}
return ret;
}
int ObExprOperator::calc_cmp_type3(ObExprResType &type,
const ObExprResType &type1,
const ObExprResType &type2,
const ObExprResType &type3,
const ObCollationType coll_type) const
{
int ret = OB_SUCCESS;
// cmp type
ObObjType cmp_type = type1.get_type();
if (is_oracle_mode() && (type1.is_blob() || type1.is_blob_locator()
|| type2.is_blob() || type2.is_blob_locator()
|| type3.is_blob() || type3.is_blob_locator())) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()), ob_obj_type_str(type2.get_type()));
} else if (OB_SUCC(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type,
type2.get_type(),
cmp_type))) {
if (OB_SUCC(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type,
cmp_type,
type3.get_type()))) {
if (OB_UNLIKELY(ObMaxType == cmp_type)) {
ret = OB_INVALID_ARGUMENT; // not compatible input
}
}
}
// collation
if (OB_SUCC(ret)) {
type.set_calc_type(cmp_type);
if (ob_is_string_or_lob_type(cmp_type)) {
ObObjMeta coll_types[3];
coll_types[0].set_collation(type1);
coll_types[1].set_collation(type2);
coll_types[2].set_collation(type3);
ret = aggregate_charsets_for_comparison(type.get_calc_meta(), coll_types, 3, coll_type);
} else if (ObRawType == cmp_type) {
type.get_calc_meta().set_collation_type(CS_TYPE_BINARY);
}
}
return ret;
}
//用于三角函数以及开方,指数,对数函数的类型推导
int ObExprOperator::calc_trig_function_result_type1(ObExprResType &type,
ObExprResType &type1,
common::ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
if (NOT_ROW_DIMENSION != row_dimension_ || ObMaxType == type1.get_type()) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
} else if (!lib::is_oracle_mode()){
type.set_double();
} else {
if (ob_is_real_type(type1.get_type())) {
type.set_double();
} else {
type.set_number();
}
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][type.get_type()].get_scale());
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE]
[type.get_type()].get_precision());
}
type1.set_calc_type(type.get_type());
//mysql/oracle 均未为三角函数、exp、ln函数的返回值添加NOT_NULL约束。
return ret;
}
int ObExprOperator::calc_trig_function_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
common::ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
if (NOT_ROW_DIMENSION != row_dimension_) {
ret = OB_ERR_INVALID_TYPE_FOR_OP; // arithmetic not support row
} else if (ObMaxType == type1.get_type() || ObMaxType == type2.get_type()) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
} else if (!lib::is_oracle_mode()) {
type.set_double();
} else {
if (ob_is_real_type(type1.get_type()) || ob_is_real_type(type2.get_type())) {
type.set_double();
} else {
type.set_number();
}
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][type.get_type()].get_scale());
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE]
[type.get_type()].get_precision());
}
type1.set_calc_type(type.get_type());
type2.set_calc_type(type.get_type());
ObExprOperator::calc_result_flag2(type, type1, type2);
return ret;
}
ObCastMode ObExprOperator::get_cast_mode() const
{
return CM_NONE;
}
ObExpr *ObExprOperator::get_rt_expr(const ObRawExpr &raw_expr) const
{
return raw_expr.rt_expr_;
}
OB_SERIALIZE_MEMBER(ObIterExprOperator, expr_id_, expr_type_);
int ObRelationalExprOperator::calc_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
if (lib::is_oracle_mode() && (type1.is_ext() || type2.is_ext())) {
// Only nested table support equality and inequality.
bool support = (T_OP_EQ == type_ || T_OP_NE == type_);
if (support && !type1.is_ext() && !type1.is_null()) {
support = false;
}
if (support && !type2.is_ext() && !type2.is_null()) {
support = false;
}
if (support && type1.is_ext()) {
support = type1.get_obj_meta().get_extend_type() == pl::PL_NESTED_TABLE_TYPE;
}
if (support && type2.is_ext()) {
support = type2.get_obj_meta().get_extend_type() == pl::PL_NESTED_TABLE_TYPE;
}
if (!support) {
ret = OB_ERR_CALL_WRONG_ARG;
LOG_WARN("wrong type", K(ret), K(type_), K(name_), K(type1), K(type2));
LOG_USER_ERROR(OB_ERR_CALL_WRONG_ARG, static_cast<int>(strlen(name_)), name_);
} else {
type.set_int32();
type.set_precision(DEFAULT_PRECISION_FOR_BOOL);
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
type.set_calc_type(type1.get_calc_type());
}
} else {
OZ(deduce_cmp_type(*this, type, type1, type2, type_ctx));
}
return ret;
}
int ObRelationalExprOperator::deduce_cmp_type(const ObExprOperator &expr,
ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx)
{
int ret = OB_SUCCESS;
ObExprResType cmp_type;
CK(NULL != type_ctx.get_session());
if (OB_FAIL(ret)) {
} else if (OB_SUCC(expr.calc_cmp_type2(cmp_type, type1, type2, type_ctx.get_coll_type()))) {
type.set_int32(); // not tinyint, compatible with MySQL
type.set_precision(DEFAULT_PRECISION_FOR_BOOL);
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
type.set_calc_collation(cmp_type);
type.set_calc_type(cmp_type.get_calc_type());
ObExprOperator::calc_result_flag2(type, type1, type2);
bool need_no_cast = can_cmp_without_cast(
type1, type2, get_cmp_op(expr.get_type()), *type_ctx.get_session());
if (!need_no_cast && is_mysql_mode()) {
// to be compatiable with mysql:
// if c1 is date or datetime, convert 'c1 = c2+1'to cast (c1 as double) = cast (c2+1 as double)
const ObRawExpr* cmp_expr = type_ctx.get_raw_expr();
const ObRawExpr* date_expr = cmp_expr->get_param_expr(0);
const ObRawExpr* other_expr = cmp_expr->get_param_expr(1);
ObObjType other_expr_type = ObMaxType;
bool is_date_op_other = false;
if (OB_ISNULL(cmp_expr) || OB_ISNULL(date_expr) || OB_ISNULL(other_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret), K(cmp_expr));
} else if (date_expr->get_result_type().get_type() == ObDateType ||
date_expr->get_result_type().get_type() == ObDateTimeType) {
other_expr_type = other_expr->get_result_type().get_type();
is_date_op_other = true;
} else if (other_expr->get_result_type().get_type() == ObDateType ||
other_expr->get_result_type().get_type() == ObDateTimeType) {
const ObRawExpr *tmp_expr = date_expr;
date_expr = other_expr;
other_expr = tmp_expr;
other_expr_type = other_expr->get_result_type().get_type();
is_date_op_other = true;
} else {
//do nothing
}
if (OB_SUCC(ret) &&
is_mysql_mode() &&
is_date_op_other &&
(ob_is_accurate_numeric_type(other_expr_type) || ob_is_real_type(other_expr_type)) &&
!(other_expr->is_const_expr() && !date_expr->is_const_expr())) {
cmp_type.set_calc_type(ObDoubleType);
type.set_calc_collation(cmp_type);
type.set_calc_type(cmp_type.get_calc_type());
}
}
if (OB_SUCC(ret)) {
type1.set_calc_type(need_no_cast ? type1.get_type() : cmp_type.get_calc_type());
type2.set_calc_type(need_no_cast ? type2.get_type() : cmp_type.get_calc_type());
if (ob_is_string_or_lob_type(cmp_type.get_calc_type())) {
type1.set_calc_collation_type(cmp_type.get_calc_collation_type());
type2.set_calc_collation_type(cmp_type.get_calc_collation_type());
} else if (ObRawType == cmp_type.get_calc_type()) {
type1.set_calc_collation_type(CS_TYPE_BINARY);
type2.set_calc_collation_type(CS_TYPE_BINARY);
}
}
}
return ret;
}
//TODO(yaoying.yyy):invoke type has not set calc_type
int ObRelationalExprOperator::calc_result_type3(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprResType &type3,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
ObExprResType cmp_type;
if (OB_SUCC(calc_cmp_type3(cmp_type, type1, type2, type3, type_ctx.get_coll_type()))) {
type.set_int32();
type.set_calc_collation(cmp_type);
type.set_calc_type(cmp_type.get_calc_type());
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
type.set_precision(DEFAULT_PRECISION_FOR_BOOL);
ObExprOperator::calc_result_flag3(type, type1, type2, type3);
if (OB_FAIL(calc_calc_type3(type1, type2, type3, type_ctx, cmp_type.get_calc_type()))) {
LOG_WARN("set calc type failed", K(type1), K(type2), K(type3), K(cmp_type), K(ret));
}
if (ob_is_string_or_lob_type(cmp_type.get_calc_type())) {
type1.set_calc_collation_type(cmp_type.get_calc_collation_type());
type2.set_calc_collation_type(cmp_type.get_calc_collation_type());
type3.set_calc_collation_type(cmp_type.get_calc_collation_type());
} else if (ObRawType == cmp_type.get_calc_type()) {
type1.set_calc_collation_type(CS_TYPE_BINARY);
type2.set_calc_collation_type(CS_TYPE_BINARY);
type3.set_calc_collation_type(CS_TYPE_BINARY);
}
}
return ret;
}
int ObRelationalExprOperator::calc_result_typeN(ObExprResType &type,
ObExprResType *types,
int64_t param_num,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(0 >= row_dimension_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or row_dimension is less than 0", K(types), K(row_dimension_), K(ret));
} else if (OB_UNLIKELY(param_num <= 0 || 2 != param_num / row_dimension_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("param_num is wrong", K(param_num), K(ret));
} else if (OB_FAIL(type.init_row_dimension(row_dimension_))) {
LOG_WARN("fail to init row dimemnsion", K(ret));
} else {
// (xiaochu.yh) MySQL处理(a,b) = (c, d)的策略是针对每一对参与比较的数字
// 进行独立第比较,并不会将所有数字转向同一个类型。例如:
// select (1, '1.000000') = ('1.00x', '1.000000');
// 1和'1.00x'会转为int然后比较,'1.00000'和'1.000000'会直接做字符串比较
ObExprResType tmp_res_type;
for (int64_t i = 0; OB_SUCC(ret) && i < row_dimension_; ++i) {
if (OB_FAIL(ObRelationalExprOperator::calc_result_type2(tmp_res_type,
types[i],
types[i + row_dimension_],
type_ctx))) {
LOG_WARN("failed to calc result types", K(ret));
} else if (OB_FAIL(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta()))) {
LOG_WARN("failed to push back cmp type", K(ret));
} else {
if (ob_is_string_or_lob_type(tmp_res_type.get_calc_type())) {
types[i].set_calc_collation_type(tmp_res_type.get_calc_collation_type());
types[i + row_dimension_].set_calc_collation_type(tmp_res_type.get_calc_collation_type());
} else if (ObRawType == tmp_res_type.get_calc_type()) {
types[i].set_calc_collation_type(CS_TYPE_BINARY);
types[i + row_dimension_].set_calc_collation_type(CS_TYPE_BINARY);
}
}
}
// overall result type
if (OB_SUCC(ret)) {
type.set_int32();
type.set_precision(DEFAULT_PRECISION_FOR_BOOL);
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
ObExprOperator::calc_result_flagN(type, types, param_num);
}
}
return ret;
}
int ObRelationalExprOperator::calc_calc_type3(ObExprResType &type1,
ObExprResType &type2,
ObExprResType &type3,
ObExprTypeCtx &type_ctx,
const ObObjType cmp_type) const
{
int ret = OB_SUCCESS;
//a(type1) between b(type2) and c(type3) <==> b<=a && a <=c
ObExprResType cmp_type21; // b <= a
ObExprResType cmp_type13; // a <= c
bool need_no_cast = false;
CK(NULL != type_ctx.get_session());
if (OB_FAIL(ret)) {
} else if (OB_FAIL(calc_cmp_type2(cmp_type21, type2, type1, type_ctx.get_coll_type()))) {
LOG_WARN("get cmp failed", K(ret), K(type2), K(type1));
} else if (OB_FAIL(calc_cmp_type2(cmp_type13, type1, type3, type_ctx.get_coll_type()))) {
LOG_WARN("get cmp failed", K(ret), K(type1), K(type3));
} else {
ObObjType type21 = cmp_type21.get_calc_type();
ObObjType type13 = cmp_type13.get_calc_type();
if (OB_LIKELY(type21 == type13 && type13 == cmp_type)) {
//type21 == type13 == cmp_type
bool need_no_cast_21 = can_cmp_without_cast(
type2, type1, get_cmp_op(type_), *type_ctx.get_session());
bool need_no_cast_13 = can_cmp_without_cast(
type1, type3, get_cmp_op(type_), *type_ctx.get_session());
need_no_cast = need_no_cast_21 && need_no_cast_13;
}
}
if (OB_SUCC(ret)) {
if (need_no_cast) {
type1.set_calc_type(type1.get_type());
type2.set_calc_type(type2.get_type());
type3.set_calc_type(type3.get_type());
} else {
type1.set_calc_type(cmp_type);
type2.set_calc_type(cmp_type);
type3.set_calc_type(cmp_type);
}
}
return ret;
}
int ObRelationalExprOperator::get_cmp_result_type3(ObExprResType &type, bool &need_no_cast,
const ObExprResType *types, const int64_t param_num, const sql::ObSQLSessionInfo &my_session)
{
int ret = OB_SUCCESS;
need_no_cast = false;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1) || OB_UNLIKELY(param_num > 3)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else if (1 == param_num) {
//this is for case when clause like case when 1 then c1 end;
type = types[0];
need_no_cast = true;
} else {
ObCollationType coll_type = CS_TYPE_INVALID;
if (OB_FAIL(my_session.get_collation_connection(coll_type))) {
LOG_WARN("fail to get_collation_connection", K(ret));
} else if (2 == param_num) {
need_no_cast = can_cmp_without_cast(types[1], types[0], CO_CMP, my_session);
if (!need_no_cast) {
ret = calc_cmp_type2(type, types[0], types[1], coll_type);
}
} else {
const ObExprResType &type1 = types[0];
const ObExprResType &type2 = types[1];
const ObExprResType &type3 = types[2];
//a(type1) between b(type2) and c(type3) <==> b<=a && a <=c
ObExprResType cmp_type21; // b <= a
ObExprResType cmp_type13; // a <= c
if (OB_FAIL(calc_cmp_type3(type, type1, type2, type3, coll_type))) {
LOG_WARN("fail to calc_cmp_type3", K(ret));
} else if (OB_FAIL(calc_cmp_type2(cmp_type21, type2, type1, coll_type))) {
LOG_WARN("get cmp failed", K(ret), K(type2), K(type1));
} else if (OB_FAIL(calc_cmp_type2(cmp_type13, type1, type3, coll_type))) {
LOG_WARN("get cmp failed", K(ret), K(type1), K(type3));
} else if (cmp_type21.get_calc_type() == cmp_type13.get_calc_type()
&& cmp_type13.get_calc_type() == type.get_calc_type()) {
//type21 == type13 == cmp_type
bool need_no_cast_21 = can_cmp_without_cast(type2, type1, CO_CMP, my_session);
bool need_no_cast_13 = can_cmp_without_cast(type1, type3, CO_CMP, my_session);
need_no_cast = need_no_cast_21 && need_no_cast_13;
}
}
}
return ret;
}
int ObRelationalExprOperator::calc_result2(ObObj &result,
const ObObj &obj1,
const ObObj &obj2,
ObExprCtx &expr_ctx,
bool is_null_safe,
ObCmpOp cmp_op) const
{
int ret = OB_SUCCESS;
//TODO::@yanhua raw
// bool need_cast = (lib::is_oracle_mode() && obj1.get_collation_type() != obj2.get_collation_type());
bool need_cast = false;
EXPR_DEFINE_CMP_CTX(result_type_.get_calc_meta(), is_null_safe, expr_ctx);
/*
* FIX ME,please. It seems that we must check obj1 and obj2 are null or not here
*
* But this is so ugly and everything will be retarded
*/
if (OB_LIKELY(!obj1.is_null() && !obj2.is_null() && cmp_op_func2_ != NULL && !need_cast)) {
if (OB_FAIL(compare_nocast(result, obj1, obj2, cmp_ctx, cmp_op, cmp_op_func2_))) {
LOG_WARN("failed to compare objects", K(ret), K(obj1), K(obj2));
}
} else if (!need_cast && OB_FAIL(compare_nocast(result, obj1, obj2, cmp_ctx, cmp_op, need_cast))) {
LOG_WARN("failed to compare objects", K(ret), K(obj1), K(obj2));
} else if (need_cast) {
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
if (OB_FAIL(compare_cast(result, obj1, obj2, cmp_ctx, cast_ctx, cmp_op))) {
LOG_WARN("failed to compare objects", K(ret), K(obj1), K(obj2));
}
}
return ret;
}
/*If you know little about vector compare in mysql, before you start to read this function,
*it is highly recommended for you to digg into this:
*http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html
*
*/
int ObRelationalExprOperator::calc_resultN(ObObj &result,
const ObObj *objs_array,
int64_t param_num,
ObExprCtx &expr_ctx,
bool is_null_safe,
ObCmpOp cmp_op) const
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(0 >= row_dimension_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("row_dimension_ is less or equal to 0",K(ret));
} else if (OB_ISNULL(objs_array)
|| OB_UNLIKELY(0 >= param_num)
|| OB_UNLIKELY(0 != param_num % row_dimension_)
|| OB_UNLIKELY(2 != param_num / row_dimension_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("objs_array or param_num or row_dimension_ is wrong",K(ret), K(param_num), K(row_dimension_));
} else if (cmp_op < CO_EQ || cmp_op >= CO_CMP) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid cmp_op argument", K(ret), K(cmp_op));
} else {
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
const ObIArray<ObExprCalcType> &cmp_types = result_type_.get_row_calc_cmp_types();
int64_t i = 0;
bool row_cnt_null = false;
ObCompareCtx cmp_ctx(ObMaxType,
CS_TYPE_INVALID,
is_null_safe,
expr_ctx.tz_offset_,
default_null_pos());
//firstly, we try to locate the first non-equal pair
for (i = 0; OB_SUCC(ret) && i < row_dimension_; ++i) {
cmp_ctx.cmp_type_ = cmp_types.at(i).get_type();
cmp_ctx.cmp_cs_type_ = cmp_types.at(i).get_collation_type();
if (OB_FAIL(compare(result, objs_array[i], objs_array[i + row_dimension_], cmp_ctx, cast_ctx, CO_NE))) {
LOG_WARN("compare failed", K(objs_array[i]), K(objs_array[i + row_dimension_]));
} else if (result.is_null()) {
row_cnt_null = true;
//no break here
} else if (result.is_true()) {
break;
}
} //end for
if (OB_SUCC(ret)) {
if (i == row_dimension_) { //all pairs are null or equal
if (row_cnt_null) { //such as (1,2) op (null, 2) , (1,2) op (null, null)
result.set_null();
} else { //all pairs are equal. such as (1,2) op (1,2)
if (CO_EQ == cmp_op || CO_LE == cmp_op || CO_GE == cmp_op) {
result.set_bool(true);
} else {
result.set_bool(false);
}
}
} else { //exist one pair whose comparison result is non-equal
if (row_cnt_null) { //such as (1,2) op (null, 3)
if (CO_NE == cmp_op) {
result.set_bool(true);
} else if (CO_EQ == cmp_op) {
result.set_bool(false);
} else {
result.set_null();
}
} else { //such as (1,2,3) op (1,2,4)
cmp_ctx.cmp_type_ = cmp_types.at(i).get_type();
cmp_ctx.cmp_cs_type_ = cmp_types.at(i).get_collation_type();
if (OB_FAIL(compare(result, objs_array[i], objs_array[i + row_dimension_], cmp_ctx, cast_ctx, cmp_op))) {
LOG_WARN("compare failed", K(objs_array[i]), K(objs_array[i + row_dimension_]), K(cmp_op));
}
}
}
}
if (OB_SUCC(ret)) {
if (false == result.is_null()) {
// 为了兼容MySQL,关系运算符的结果类型都设置为int32
result.set_int(ObInt32Type, result.get_int());
}
}
}
return ret;
}
bool ObRelationalExprOperator::is_int_cmp_const_str(const ObExprResType *type1,
const ObExprResType *type2,
ObObjType &cmp_type)
{
UNUSED(type1);
UNUSED(type2);
UNUSED(cmp_type);
return false;
}
int ObRelationalExprOperator::assign(const ObExprOperator &other)
{
int ret = OB_SUCCESS;
const ObRelationalExprOperator *tmp_other = dynamic_cast<const ObRelationalExprOperator *>(&other);
if (OB_UNLIKELY(NULL == tmp_other)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument. wrong type for other", K(ret), K(other));
} else if (OB_LIKELY(this != tmp_other)) {
if (OB_FAIL(ObExprOperator::assign(other))) {
LOG_WARN("copy in Base class ObExprOperator failed", K(ret));
} else {
this->cmp_op_func2_ = tmp_other->cmp_op_func2_;
}
}
return ret;
}
int ObRelationalExprOperator::set_cmp_func(const ObObjType type1,
const ObObjType type2)
{
int ret = OB_SUCCESS;
ObCmpOp cmp_op = get_cmp_op(type_);
ObObjTypeClass tc1 = ob_obj_type_class(type1);
ObObjTypeClass tc2 = ob_obj_type_class(type2);
if (OB_FAIL(ObObjCmpFuncs::get_cmp_func(tc1, tc2, cmp_op, cmp_op_func2_))) {
LOG_WARN("get cmp func failed", K(type1), K(type2), K(tc1), K(tc2), K(ret));
}
return ret;
}
int ObRelationalExprOperator::get_pl_udt_cmp_func(const ObObjType type1,
const ObObjType type2,
const ObCmpOp cmp_op,
common::obj_cmp_func &cmp_fp)
{
int ret = OB_SUCCESS;
// ObCmpOp cmp_op = CO_LT;
ObObjTypeClass tc1 = ob_obj_type_class(type1);
ObObjTypeClass tc2 = ob_obj_type_class(type2);
if (OB_FAIL(ObObjCmpFuncs::get_cmp_func(tc1, tc2, cmp_op, cmp_fp))) {
LOG_WARN("get cmp func failed", K(type1), K(type2), K(tc1), K(tc2), K(ret));
}
return ret;
}
int ObRelationalExprOperator::pl_udt_compare2(CollectionPredRes &cmp_result,
const ObObj &obj1,
const ObObj &obj2,
ObExecContext &exec_ctx,
const ObCmpOp cmp_op)
{
int ret = OB_SUCCESS;
pl::ObPLCollection *c1 = reinterpret_cast<pl::ObPLCollection *>(obj1.get_ext());
pl::ObPLCollection *c2 = reinterpret_cast<pl::ObPLCollection *>(obj2.get_ext());
#define SET_CMP_RESULT(eq_cond, ne_cond, other_cond) \
do { \
cmp_result = CO_EQ == cmp_op ? eq_cond : CO_NE == cmp_op ? ne_cond : other_cond;\
} while(0)
/* 比较规则:
* 1、去除null之后相等,但是c1或c2包含null,结果是null
* 2、c2未初始化,结果是null
* 3、c1未初始化,结果是null
* 4、nt1 in nt1, true, 但是,两个未初始化集合比较,结果为null,空集和空集比较,true
* 5、除上面情况,不相等,false
* 6、其它情况,true
*/
if (OB_ISNULL(c1) || OB_ISNULL(c2)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("compare udt failed due to null udt", K(ret), K(obj1), K(obj2));
} else if (pl::PL_NESTED_TABLE_TYPE != c1->get_type()
|| pl::PL_NESTED_TABLE_TYPE != c2->get_type()) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "udt compare except nested table");
LOG_WARN("not support udt compare except nested table", K(ret), K(c1), K(c2));
} else if (c1->get_element_type().get_obj_type() != c2->get_element_type().get_obj_type()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("not support udt compare with different elem type", K(ret), K(c1), K(c2));
} else if (!c1->is_inited() || !c2->is_inited()) {
cmp_result = CollectionPredRes::COLL_PRED_NULL;
} else if ((c1->get_actual_count() != c2->get_actual_count())) {
SET_CMP_RESULT(COLL_PRED_FALSE, COLL_PRED_TRUE, COLL_PRED_INVALID);
} else if (0 == c1->get_actual_count() && 0 == c2->get_actual_count()) {
SET_CMP_RESULT(COLL_PRED_TRUE, COLL_PRED_FALSE, COLL_PRED_INVALID);
} else if (c1->is_contain_null_val() || c2->is_contain_null_val()) {
cmp_result = CollectionPredRes::COLL_PRED_NULL;
} else if (c1 == c2) {
// self compare
SET_CMP_RESULT(COLL_PRED_TRUE, COLL_PRED_FALSE, COLL_PRED_INVALID);
} else {
common::ObArray<const ObObj *> c1_copy, c2_copy;
// for (int64_t i = 0; OB_SUCC(ret) && i < c1->get_count(); ++i) {
// OZ (c1_copy.push_back(reinterpret_cast<const ObObj*>(c1->get_data()) + i));
// OZ (c2_copy.push_back(reinterpret_cast<const ObObj*>(c2->get_data()) + i));
// }
bool del_flag = false;
for (int64_t i = 0; OB_SUCC(ret) && i < c1->get_count(); ++i) {
const ObObj *elem = reinterpret_cast<const ObObj*>(c1->get_data()) + i;
CK (OB_NOT_NULL(elem));
if (OB_SUCC(ret)) {
if (elem->is_null()) {
} else if (c1->is_elem_deleted(i, del_flag)) {
LOG_WARN("failed to test if element is deleted", K(*elem), K(ret), K(i));
} else {
if (!del_flag) {
OZ (c1_copy.push_back(elem));
}
}
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < c2->get_count(); ++i) {
const ObObj *elem = reinterpret_cast<const ObObj*>(c2->get_data()) + i;
CK (OB_NOT_NULL(elem));
if (OB_SUCC(ret)) {
if (elem->is_null()) {
} else if (c2->is_elem_deleted(i, del_flag)) {
LOG_WARN("failed to test if element is deleted", K(*elem), K(ret), K(i));
} else {
if (!del_flag) {
OZ (c2_copy.push_back(elem));
}
}
}
}
if (OB_SUCC(ret)) {
// 小于比较函数
obj_cmp_func lt_cmp_fp;
const ObTimeZoneInfo *tz_info = get_timezone_info(exec_ctx.get_my_session());
int64_t tz_off;
CK(NULL != tz_info);
OZ(get_tz_offset(tz_info, tz_off));
if (OB_FAIL(ret)) {
} else if (OB_FAIL(get_pl_udt_cmp_func(c1->get_element_type().get_obj_type(),
c2->get_element_type().get_obj_type(),
CO_LT,
lt_cmp_fp))) {
LOG_WARN("set compare function failed.", K(ret), K(obj1), K(obj2));
} else {
ObCompareCtx cmp_ctx(c1->get_element_type().get_obj_type(),
c1->get_element_type().get_collation_type(),
false /* null safe */,
tz_off,
default_null_pos());
struct udtComparer{
udtComparer(ObCompareCtx &cmp_ctx, common::obj_cmp_func cmp_func) :
cmp_ctx_(cmp_ctx),
cmp_func_(cmp_func) {}
bool operator()(const ObObj *&e1, const ObObj *&e2) {
int cmpRes = cmp_func_(*e1, *e2, cmp_ctx_);
return cmpRes;
}
ObCompareCtx &cmp_ctx_;
common::obj_cmp_func cmp_func_;
};
udtComparer uc(cmp_ctx, lt_cmp_fp);
const ObObj **first = &c1_copy.at(0);
std::sort(first, first + c1_copy.count(), uc);
first = &c2_copy.at(0);
std::sort(first, first + c2_copy.count(), uc);
int cmp_res = 1;
// 可能是等值或者不等值
common::obj_cmp_func eq_cmp_fp;
ObObjType type1 = c1->get_element_type().get_obj_type();
ObObjType type2 = c2->get_element_type().get_obj_type();
if (OB_FAIL(get_pl_udt_cmp_func(type1, type2, CO_EQ, eq_cmp_fp))) {
LOG_WARN("get cmp func failed", K(type1), K(type2), K(cmp_op), K(ret));
} else {
for (int64_t i = 0; 1 == cmp_res && i < c1->get_count(); ++i) {
cmp_res = eq_cmp_fp(*(c1_copy.at(i)), *(c2_copy.at(i)), cmp_ctx);
}
}
cmp_result = static_cast<CollectionPredRes>(CO_EQ == cmp_op ? cmp_res : !cmp_res);
}
}
}
return ret;
}
int ObRelationalExprOperator::eval_pl_udt_compare(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
ObDatum *l = NULL;
ObDatum *r = NULL;
OZ(expr.eval_param_value(ctx, l, r));
if (OB_SUCC(ret)) {
if (l->is_null() || r->is_null()) {
expr_datum.set_null();
} else {
CollectionPredRes cmp_res = CollectionPredRes::COLL_PRED_INVALID;
OZ(pl_udt_compare2(cmp_res, *l->extend_obj_, *r->extend_obj_,
ctx.exec_ctx_, get_cmp_op(expr.type_)));
if (OB_SUCC(ret)) {
switch (cmp_res) {
case COLL_PRED_NULL: {
expr_datum.set_null();
break;
}
case COLL_PRED_TRUE:
case COLL_PRED_FALSE: {
expr_datum.set_int32(cmp_res);
break;
}
default:
expr_datum.set_int32(0);
}
}
}
}
return ret;
}
OB_SERIALIZE_MEMBER((ObSubQueryRelationalExpr, ObExprOperator),
subquery_key_,
left_is_iter_,
right_is_iter_);
int ObSubQueryRelationalExpr::assign(const ObExprOperator &other)
{
int ret = OB_SUCCESS;
const ObSubQueryRelationalExpr *tmp_other = dynamic_cast<const ObSubQueryRelationalExpr *>(&other);
if (OB_UNLIKELY(NULL == tmp_other)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument. wrong type for other", K(ret), K(other));
} else if (OB_LIKELY(this != tmp_other)) {
if (OB_FAIL(ObExprOperator::assign(other))) {
LOG_WARN("copy in Base class ObExprOperator failed", K(ret));
} else {
this->subquery_key_ = tmp_other->subquery_key_;
this->left_is_iter_ = tmp_other->left_is_iter_;
this->right_is_iter_ = tmp_other->right_is_iter_;
}
}
return ret;
}
//类型推导中本应该做兼容类型检查,但是目前子查询还没有实现类型检查,所以暂时不做参数检查
//比较操作符的返回类型一定是bool类型
int ObSubQueryRelationalExpr::calc_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
ObExprResType tmp_res_type;
CK(NULL != type_ctx.get_session());
OZ(type.init_row_dimension(1));
if (OB_SUCC(ret)) {
// static typing engine enabled, same with ObRelationalExprOperator::calc_result_type
OZ(ObRelationalExprOperator::deduce_cmp_type(*this, type, type1, type2, type_ctx));
OZ(type.get_row_calc_cmp_types().push_back(type.get_calc_meta()));
}
return ret;
}
int ObSubQueryRelationalExpr::calc_result_typeN(ObExprResType &type,
ObExprResType *types,
int64_t param_num,
ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
CK(NULL != type_ctx.get_session());
if (OB_FAIL(ret)) {
} else if (OB_ISNULL(types) || OB_UNLIKELY(0 >= row_dimension_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or row_dimension_ is less equal than 0",
K(types), K(row_dimension_), K(ret));
} else if (OB_UNLIKELY(param_num <= 0 || 2 != param_num / row_dimension_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("param_num is wrong", K(ret));
} else if (OB_FAIL(type.init_row_dimension(row_dimension_))) {
LOG_WARN("fail to init row dimension", K(ret));
}
if (OB_SUCC(ret)) {
for (int64_t i = 0; OB_SUCC(ret) && i < row_dimension_; i++) {
ObExprResType tmp_res_type;
OZ(ObRelationalExprOperator::deduce_cmp_type(
*this, tmp_res_type, types[i], types[i + row_dimension_], type_ctx));
OZ(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta()));
if (OB_SUCC(ret)) {
if (ob_is_string_type(tmp_res_type.get_calc_type())) {
types[i].set_calc_collation_type(tmp_res_type.get_calc_collation_type());
types[i + row_dimension_].set_calc_collation_type(tmp_res_type.get_calc_collation_type());
} else if (ObRawType == tmp_res_type.get_calc_type()) {
types[i].set_calc_collation_type(CS_TYPE_BINARY);
types[i + row_dimension_].set_calc_collation_type(CS_TYPE_BINARY);
}
}
}
if (OB_SUCC(ret)) {
type.set_int32();
type.set_precision(DEFAULT_PRECISION_FOR_BOOL);
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
ObExprOperator::calc_result_flagN(type, types, param_num);
}
}
return ret;
}
int ObSubQueryRelationalExpr::calc_result2(ObObj &result,
const ObObj &obj1,
const ObObj &obj2,
ObExprCtx &expr_ctx) const
{
//在calc_result2这个接口中右操作符一定是一个迭代器
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!right_is_iter_) || OB_ISNULL(expr_ctx.subplan_iters_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("right_is_iter_ is wrong or expr_ctx.subplan_iters_ is null",
K(right_is_iter_), K(expr_ctx.subplan_iters_),K(ret));
} else {
int64_t subquery_idx = OB_INVALID_INDEX;
ObNewRow tmp_row;
ObNewRow *left_row = NULL;
ObNewRowIterator *left_row_iter = NULL;
if (left_is_iter_) {
int64_t left_idx = OB_INVALID_INDEX;
if (OB_FAIL(obj1.get_int(left_idx))) {
LOG_WARN("get left subquery index failed", K(ret), K(obj1));
} else if (OB_ISNULL(left_row_iter = expr_ctx.subplan_iters_->at(left_idx))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("get row iterator failed", K(left_idx));
} else if (OB_FAIL(left_row_iter->get_next_row(left_row))) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
result.set_null();
} else {
LOG_WARN("get next row from left row iterator failed", K(ret));
}
}
} else {
tmp_row.cells_ = const_cast<ObObj*>(&obj1);
tmp_row.count_ = 1;
left_row = &tmp_row;
}
if (OB_SUCC(ret) && NULL != left_row) {
if (OB_FAIL(obj2.get_int(subquery_idx))) {
LOG_WARN("get subquery index failed", K(ret), K(obj2));
} else if (T_WITH_ALL == subquery_key_) {
if (OB_FAIL(calc_result_with_all(result, *left_row, subquery_idx, expr_ctx))) {
LOG_WARN("calc result with all failed", K(ret));
}
} else if (T_WITH_ANY == subquery_key_) {
if (OB_FAIL(calc_result_with_any(result, *left_row, subquery_idx, expr_ctx))) {
LOG_WARN("calc result with any failed", K(ret));
}
} else if (T_WITH_NONE == subquery_key_) {
//向量比较,出现这种情况只可能是左右两边都是子查询
if (OB_UNLIKELY(!left_is_iter_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("left_is_iter_ is wrong", K(ret));
} else if (OB_FAIL(calc_result_with_none(result, *left_row, subquery_idx, expr_ctx))) {
LOG_WARN("calc result with none failed", K(ret));
}
}
}
//for the comparison of subquery, if the left param is row iterator,
//we must check the row count of the left row iterator
//the left row iterator can only return one row
if (OB_SUCC(ret) && left_is_iter_) {
ObNewRow *tmp_left_row = NULL;
if (OB_FAIL(left_row_iter->get_next_row(tmp_left_row))) {
if (OB_LIKELY(OB_ITER_END == ret)) {
ret = OB_SUCCESS; //第一次迭代出了数据,无法迭代出第二行数据,符合with none的语义,返回OB_SUCCESS
} else {
LOG_WARN("get next row from iter failed", K(ret));
}
} else {
//第二次又迭代出数据,不符合向量的语义,所以应该对外报错
ret = OB_SUBQUERY_TOO_MANY_ROW;
}
}
}
return ret;
}
int ObSubQueryRelationalExpr::calc_resultN(ObObj &result,
const ObObj *param_array,
int64_t param_num,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(param_num <= 2)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("param_num is wrong", K(param_array), K(ret));
} else if (OB_UNLIKELY(left_is_iter_ && right_is_iter_)
|| OB_ISNULL(expr_ctx.subplan_iters_)
|| OB_ISNULL(param_array)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("left_is_iter_ and right_is_iter cann't be same true",
K(param_num), K(left_is_iter_), K(right_is_iter_),
K(expr_ctx.subplan_iters_), K(param_array), K(ret));
} else {
//对于calc_resultN接口来说,param_array至少有一个iterator参数,但是又不都是iterator参数
int64_t subquery_idx = OB_INVALID_ID;
ObNewRow tmp_row;
ObNewRow *left_row = NULL;
ObNewRowIterator *row_iter = NULL;
if (left_is_iter_) {
int64_t left_idx = OB_INVALID_INDEX;
const ObObj &idx_obj = param_array[0];
if (OB_FAIL(idx_obj.get_int(left_idx))) {
LOG_WARN("get left subquery index failed", K(ret), K(idx_obj));
} else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(left_idx))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("get row iterator failed", K(left_idx));
} else if (OB_FAIL(row_iter->get_next_row(left_row))) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
result.set_null();
} else {
LOG_WARN("get next row from left row iterator failed", K(ret));
}
} else {
ObNewRow *tmp_left_row = NULL;
tmp_row.cells_ = const_cast<ObObj*>(&param_array[1]);
tmp_row.count_ = param_num - 1;
if (OB_ISNULL(left_row)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("left_row is null", K(left_row), K(ret));
} else if (OB_FAIL(compare_single_row(*left_row, tmp_row, expr_ctx, result))) {
LOG_WARN("compare single row failed", K(ret));
} else if (OB_FAIL(row_iter->get_next_row(tmp_left_row))) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS; //第一次迭代出了数据,无法迭代出第二行数据,符合with none的语义,返回OB_SUCCESS
} else {
LOG_WARN("get next row from iter failed", K(ret));
}
} else {
//第二次又迭代出数据,不符合向量的语义,所以应该对外报错
ret = OB_SUBQUERY_TOO_MANY_ROW;
}
}
} else if (right_is_iter_) {
tmp_row.cells_ = const_cast<ObObj*>(param_array);
tmp_row.count_ = param_num - 1;
left_row = &tmp_row;
const ObObj &idx_obj = param_array[param_num - 1];
if (OB_ISNULL(left_row)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("left_row is null", K(left_row), K(ret));
} else if (OB_FAIL(idx_obj.get_int(subquery_idx))) {
LOG_WARN("get subquery index failed", K(ret));
} else if (T_WITH_ALL == subquery_key_) {
if (OB_FAIL(calc_result_with_all(result, *left_row, subquery_idx, expr_ctx))) {
LOG_WARN("calc result with all failed", K(ret));
}
} else if (T_WITH_ANY == subquery_key_) {
if (OB_FAIL(calc_result_with_any(result, *left_row, subquery_idx, expr_ctx))) {
LOG_WARN("calc result with any failed", K(ret));
}
} else if (T_WITH_NONE == subquery_key_) {
if (OB_FAIL(calc_result_with_none(result, *left_row, subquery_idx, expr_ctx))) {
LOG_WARN("calc result with none failed", K(ret));
}
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("left_is_iter_ and right_is_iter are all false", K(ret));
}
}
return ret;
}
int ObSubQueryRelationalExpr::call(ObObj *stack,
int64_t &stack_size,
ObExprCtx &expr_ctx) const
{
ObObj result;
int ret = OB_SUCCESS;
if (OB_ISNULL(stack) || OB_UNLIKELY(real_param_num_ < 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("stack is null or the param is wrong", K(stack),
K(real_param_num_), K(ret));
} else if (OB_UNLIKELY(real_param_num_ > stack_size)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("stack is null or the param is wrong",
K(stack_size), K(real_param_num_), K(ret));
} else {
//subquery的运算和普通运算不一样,没有参数维度和向量维度的概念,
//subquery相关的表达式运算,左边参数是non-subquery的参数个数,右边是一个subquery ref参数
//对于exist(subquery)参数个数为1,参数只有subquery ref operator
//对于c1>(subquery)这种情况,参数个数为2,左边参数是column_ref(c1),右边是subquery_ref index
//对于(c1, c2)=(subquery)这种情况,参数个数是3,左边参数是ccolumn_ref(c1), column_ref(c2),
// 右边参数是subquery_ref index
switch (real_param_num_) {
case 1: {
if (OB_FAIL(calc_result1(result, stack[stack_size - 1], expr_ctx))) {
LOG_WARN("fail to calc result1", K(ret), K(stack_size));
} else {
stack[stack_size - 1] = result;
}
break;
}
case 2: {
if (OB_FAIL(calc_result2(result,
stack[stack_size - 2],
stack[stack_size - 1],
expr_ctx))) {
LOG_WARN("fail to calc result1", K(ret), K(stack_size));
} else {
stack[stack_size - 2] = result;
stack_size--;
}
break;
}
default: {
if (OB_FAIL(this->calc_resultN(result,
&stack[stack_size - real_param_num_],
real_param_num_,
expr_ctx))) {
LOG_WARN("fail to calc resultN", K(ret), K(stack_size));
} else {
stack[stack_size - real_param_num_] = result;
stack_size -= real_param_num_ - 1;
}
break;
} // end switch
}
}
return ret;
}
int ObSubQueryRelationalExpr::eval(common::ObExprCtx &expr_ctx, common::ObObj &val,
common::ObObj *params, int64_t param_num) const
{
int ret = OB_SUCCESS;
new (&val) ObObj();
if (OB_ISNULL(params) || OB_UNLIKELY(param_num < 0)
|| OB_UNLIKELY(real_param_num_ != param_num)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(param_num), K(real_param_num_));
} else {
switch (real_param_num_) {
case 1: {
ret = calc_result1(val, params[0], expr_ctx);
break;
}
case 2: {
ret = calc_result2(val, params[0], params[1], expr_ctx);
break;
}
default: {
ret = calc_resultN(val, params, param_num, expr_ctx);
}
}
if (OB_FAIL(ret)) {
LOG_WARN("calc result failed", K(ret), K(param_num_), K(name_), K(get_type_name(type_)));
}
}
return ret;
}
int ObSubQueryRelationalExpr::calc_result_with_none(ObObj &result,
const ObNewRow &left_row,
int64_t subquery_idx,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
ObNewRowIterator *row_iter = NULL;
ObNewRow *row = NULL;
if (OB_ISNULL(expr_ctx.subplan_iters_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("expr_ctx.subplan_iters_ is null");
} else if (OB_UNLIKELY(subquery_idx < 0 || subquery_idx >= expr_ctx.subplan_iters_->count())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery_idx is invalied", K(subquery_idx),
"iter count", expr_ctx.subplan_iters_->count());
} else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(subquery_idx))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery result iterator is null");
} else if (OB_FAIL(row_iter->get_next_row(row))) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
result.set_null();
} else {
LOG_WARN("get next row from row iterator failed", K(ret));
}
} else {
if (OB_ISNULL(row)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("row is null");
} else if (OB_UNLIKELY(left_row.get_count() != row->get_count())) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("left_row and right row is not equal");
} else {
if (OB_FAIL(compare_single_row(left_row, *row, expr_ctx, result))) {
LOG_WARN("compare single row failed", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(row_iter->get_next_row(row))) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS; //第一次迭代出了数据,无法迭代出第二行数据,符合with none的语义,返回OB_SUCCESS
} else {
LOG_WARN("get next row from iter failed", K(ret));
}
} else {
//第二次又迭代出数据,不符合向量的语义,所以应该对外报错
ret = OB_SUBQUERY_TOO_MANY_ROW;
}
}
return ret;
}
/**
* ALL的语义是所有值比较都为true整个表达式才为true
* 如果有一个值的结果为false,那么整个表达式的条件一定不成立,结果为false
* 如果有一个值的结果为NULL(NULL的语义是结果不确定)
* 那么需要看剩下的结果,如果剩下的结果都为true,那么应该返会NULL,因为有不确定的行值
* 其它情况返回true
*/
int ObSubQueryRelationalExpr::calc_result_with_all(ObObj &result,
const ObNewRow &left_row,
int64_t subquery_idx,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
ObNewRowIterator *row_iter = NULL;
ObNewRow *row = NULL;
ObObj tmp_result;
bool cnt_null = false;
if (OB_ISNULL(expr_ctx.subplan_iters_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery_idx is invalied", K(expr_ctx.subplan_iters_), K(ret));
} else if (OB_UNLIKELY(subquery_idx < 0 || subquery_idx >= expr_ctx.subplan_iters_->count())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery_idx is invalied", K(subquery_idx), "iter count",
expr_ctx.subplan_iters_->count());
} else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(subquery_idx))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery result iterator is null");
} else {
//mysql和oracle的行为是如果ALL集合是空集,那么比较结果为true,所以初始化为true
tmp_result.set_bool(true);
while (OB_SUCC(ret) && OB_SUCC(row_iter->get_next_row(row))) {
if (OB_ISNULL(row)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("row is null",K(ret));
} else if (OB_UNLIKELY(left_row.get_count() != row->get_count())) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("left_row and right_row is not equal",K(ret));
} else {
if (OB_FAIL(compare_single_row(left_row, *row, expr_ctx, tmp_result))) {
LOG_WARN("compare single row failed", K(ret));
} else if (OB_UNLIKELY(!tmp_result.is_int32() && !tmp_result.is_null())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("result type type is invalid", K(tmp_result));
} else if (tmp_result.is_false()) {
//只要有一个元素不满足条件,整个表达式就为false,所以需要跳出循环
break;
} else if (tmp_result.is_null()) {
cnt_null = true;
}
}
}
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
if (OB_SUCC(ret)) {
if (tmp_result.is_true() && cnt_null) {
tmp_result.set_null();
}
result = tmp_result;
}
}
return ret;
}
/**
* ANY的语义是集合中存在值比较为true整个表达式就为true
* 如果有一个值的结果为true,那么整个表达式的条件一定成立,结果为true
* 如果存在值的结果为NULL(NULL的语义是结果不确定)
* 那么需要看剩下的结果,如果剩下的结果都为false,那么应该返会NULL,因为有不确定的值
* 其它情况返回true
*/
int ObSubQueryRelationalExpr::calc_result_with_any(ObObj &result,
const ObNewRow &left_row,
int64_t subquery_idx,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
ObNewRowIterator *row_iter = NULL;
ObNewRow *row = NULL;
ObObj tmp_result;
bool cnt_null = false;
if (OB_ISNULL(expr_ctx.subplan_iters_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery_idx is invalied", K(expr_ctx.subplan_iters_), K(ret));
} else if (OB_UNLIKELY(subquery_idx < 0 || subquery_idx >= expr_ctx.subplan_iters_->count())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery_idx is invalied", K(subquery_idx),
"iter count", expr_ctx.subplan_iters_->count());
} else if (OB_ISNULL(row_iter = expr_ctx.subplan_iters_->at(subquery_idx))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subquery result iterator is null");
} else {
//mysql和oracle的行为是如果ANY集合是空集,那么比较结果为false,所以初始化为false
tmp_result.set_bool(false);
while (OB_SUCC(ret) && OB_SUCC(row_iter->get_next_row(row))) {
if (OB_UNLIKELY(left_row.get_count() != row->get_count())) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("left_row and right_row is not equal", K(ret));
} else {
if (OB_FAIL(compare_single_row(left_row, *row, expr_ctx, tmp_result))) {
LOG_WARN("compare single row failed", K(ret));
} else if (OB_UNLIKELY(!tmp_result.is_int32() && !tmp_result.is_null())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("result type type is invalid", K(tmp_result), K(ret));
} else if(tmp_result.is_true()) {
break;
//只要有一个元素满足条件,结果就为true,所以跳出迭代
} else if (tmp_result.is_null()) {
cnt_null = true;
}
}
}
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
if (OB_SUCC(ret)) {
if (tmp_result.is_false() && cnt_null) {
tmp_result.set_null();
}
result = tmp_result;
}
}
return ret;
}
int ObSubQueryRelationalExpr::compare_obj(common::ObExprCtx &expr_ctx,
const ObObj &obj1,
const ObObj &obj2,
const ObExprCalcType &cmp_type,
bool is_null_safe,
ObObj &result) const
{
int ret = OB_SUCCESS;
EXPR_DEFINE_CMP_CTX(cmp_type, is_null_safe, expr_ctx);
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_WARN_ON_FAIL);
if (OB_FAIL(ObRelationalExprOperator::compare_cast(result, obj1, obj2, cmp_ctx, cast_ctx, CO_CMP))) {
LOG_WARN("Compare expression failed", K(ret));
}
return ret;
}
int ObSubQueryRelationalExpr::compare_single_row(const ObNewRow &left_row,
const ObNewRow &right_row,
ObExprCtx &expr_ctx,
ObObj &result) const
{
UNUSED(left_row);
UNUSED(right_row);
UNUSED(expr_ctx);
UNUSED(result);
return OB_NOT_IMPLEMENT;
}
int ObSubQueryRelationalExpr::get_param_types(
const ObRawExpr &param, const bool is_iter, ObIArray<ObObjMeta> &types) const
{
int ret = OB_SUCCESS;
if (param.get_expr_type() == T_OP_ROW) {
for (int64_t i = 0; OB_SUCC(ret) && i < param.get_param_count(); i++) {
const ObRawExpr *e = param.get_param_expr(i);
CK(NULL != e);
OZ(types.push_back(e->get_result_meta()));
}
} else if (param.get_expr_type() == T_REF_QUERY && is_iter) {
const ObQueryRefRawExpr &ref = static_cast<const ObQueryRefRawExpr &>(param);
FOREACH_CNT_X(t, ref.get_column_types(), OB_SUCC(ret)) {
OZ(types.push_back(*t));
}
} else {
OZ(types.push_back(param.get_result_meta()));
}
return ret;
}
int ObSubQueryRelationalExpr::cg_expr(ObExprCGCtx &op_cg_ctx,
const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
int ret = OB_SUCCESS;
ObSEArray<ObObjMeta, 1> left_types;
ObSEArray<ObObjMeta, 1> right_types;
void **funcs = NULL;
CK(NULL != op_cg_ctx.allocator_);
CK(2 == raw_expr.get_param_count());
CK(NULL != raw_expr.get_param_expr(0));
CK(NULL != raw_expr.get_param_expr(1));
// row_dimension_ is set for old expr engine in ObExprGeneratorImpl, can not used here
OZ(get_param_types(*raw_expr.get_param_expr(0), left_is_iter_, left_types));
OZ(get_param_types(*raw_expr.get_param_expr(1), right_is_iter_, right_types));
if (OB_FAIL(ret)) {
} else if (left_types.empty() || left_types.count() != right_types.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("operand cnt mismatch",
K(ret), K(left_types.count()), K(right_types.count()));
} else if (OB_ISNULL(funcs = (void **)op_cg_ctx.allocator_->alloc(
sizeof(void *) * left_types.count()))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("alloc memory failed", K(ret));
} else {
rt_expr.inner_func_cnt_ = left_types.count();
rt_expr.inner_functions_ = funcs;
for (int64_t i = 0; OB_SUCC(ret) && i < rt_expr.inner_func_cnt_; i++) {
auto &l = left_types.at(i);
auto &r = right_types.at(i);
if (ObDatumFuncs::is_string_type(l.get_type())
&& ObDatumFuncs::is_string_type(r.get_type())) {
CK(l.get_collation_type() == r.get_collation_type());
}
if (OB_SUCC(ret)) {
funcs[i] = (void *)ObExprCmpFuncsHelper::get_datum_expr_cmp_func(
l.get_type(), r.get_type(), lib::is_oracle_mode(), l.get_collation_type());
CK(NULL != funcs[i]);
}
}
if (OB_SUCC(ret)) {
ExtraInfo &info = ExtraInfo::get_info(rt_expr);
info.subquery_key_ = subquery_key_;
info.left_is_iter_ = left_is_iter_;
info.right_is_iter_ = right_is_iter_;
rt_expr.eval_func_ = &subquery_cmp_eval;
}
}
return ret;
}
int ObSubQueryRelationalExpr::check_exists(const ObExpr &expr, ObEvalCtx &ctx, bool &exists)
{
int ret = OB_SUCCESS;
ObDatum *v = NULL;
ObSubQueryIterator *iter = NULL;
exists = false;
if (1 != expr.arg_cnt_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected argument count", K(ret));
} else if (OB_FAIL(expr.args_[0]->eval(ctx, v))) {
LOG_WARN("NULL subquery ref info returned", K(ret));
} else if (OB_FAIL(ObExprSubQueryRef::get_subquery_iter(
ctx, ObExprSubQueryRef::Extra::get_info(v->get_int()), iter))) {
LOG_WARN("get subquery iterator failed", K(ret));
} else if (OB_ISNULL(iter)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL subquery iterator", K(ret));
} else if (OB_FAIL(iter->rewind())) {
LOG_WARN("start iterate failed", K(ret));
} else {
bool found_in_hash_map = false;
bool is_hash_enabled = iter->has_hashmap();
if (is_hash_enabled) {
ObDatum out;
if (OB_FAIL(iter->get_curr_probe_row())) {
LOG_WARN("failed to get probe row", K(ret));
} else if (OB_FAIL(iter->get_refactored(out))) {
if (OB_HASH_NOT_EXIST != ret) {
LOG_WARN("failed to find in hash map", K(ret));
} else {
ret = OB_SUCCESS;
}
} else {
found_in_hash_map = true;
exists = out.get_bool();
}
}
if (OB_FAIL(ret) || found_in_hash_map) {
} else if (OB_FAIL(iter->get_next_row())) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
exists = false;
} else {
LOG_WARN("get next row failed", K(ret));
}
} else {
exists = true;
}
if (OB_SUCC(ret) && is_hash_enabled
&& iter->probe_row_.cnt_ > 0
&& !found_in_hash_map) {
//now we can insert curr row and curr result into hashmap
//first to get arena allocator from sp_iter to deep copy row
ObDatum value;
DatumRow row_key;
row_key.cnt_ = iter->probe_row_.cnt_;
//first check memory is enough
int64_t need_size = sizeof(ObDatum) + sizeof(int64_t);
for (int64_t i = 0; i < iter->probe_row_.cnt_; ++i) {
need_size += (iter->probe_row_.elems_[i].len_ + sizeof(ObDatum));
}
bool can_insert = iter->check_can_insert(need_size);
ObIAllocator *alloc = nullptr;
if (!can_insert) {
//memory is exceed, do not insert new rows
} else if (OB_FAIL(iter->get_arena_allocator(alloc)) || OB_ISNULL(alloc)) {
LOG_WARN("failed to get arena allocator", K(ret));
} else if (OB_ISNULL(value.ptr_ = static_cast<char *>(alloc->alloc(sizeof(int64_t))))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory for value", K(ret));
} else if (FALSE_IT(value.pack_ = sizeof(int64_t))) {
} else if (OB_ISNULL(row_key.elems_
= static_cast<ObDatum *> (alloc->alloc(sizeof(ObDatum) * row_key.cnt_)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc memory for row key", K(ret), K(row_key.cnt_));
} else {
value.set_bool(exists);
for (int64_t i = 0; OB_SUCC(ret) && i < row_key.cnt_; ++i) {
if (OB_FAIL(row_key.elems_[i].deep_copy(iter->probe_row_.elems_[i], *alloc))) {
LOG_WARN("failed to copy probe row", K(ret));
}
}
if (OB_SUCC(ret) && OB_FAIL(iter->set_refactored(row_key, value, need_size))) {
LOG_WARN("failed to insert into hashmap", K(ret));
}
}
}
}
return ret;
}
int ObSubQueryRelationalExpr::setup_row(
ObExpr **expr, ObEvalCtx &ctx, const bool is_iter, const int64_t cmp_func_cnt,
ObSubQueryIterator *&iter, ObExpr **&row, ObEvalCtx *&used_ctx)
{
int ret = OB_SUCCESS;
used_ctx = &ctx;
if (is_iter) {
ObDatum *v = NULL;
if (OB_FAIL(expr[0]->eval(ctx, v))) {
LOG_WARN("expr evaluate failed", K(ret));
} else if (v->is_null()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL subquery ref info returned", K(ret));
} else if (OB_FAIL(ObExprSubQueryRef::get_subquery_iter(
ctx, ObExprSubQueryRef::Extra::get_info(v->get_int()), iter))) {
LOG_WARN("get subquery iterator failed", K(ret));
} else if (OB_ISNULL(iter) || cmp_func_cnt != iter->get_output().count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL subquery iterator", K(ret), KP(iter), K(cmp_func_cnt));
} else if (OB_FAIL(iter->rewind())) {
LOG_WARN("start iterate failed", K(ret));
} else {
row = &const_cast<ExprFixedArray &>(iter->get_output()).at(0);
used_ctx = &iter->get_eval_ctx();
}
} else if (T_OP_ROW == expr[0]->type_) {
if (cmp_func_cnt != expr[0]->arg_cnt_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cmp function count mismatch", K(ret), K(cmp_func_cnt), K(*expr[0]));
} else {
row = expr[0]->args_;
}
} else {
row = expr;
}
return ret;
}
int ObSubQueryRelationalExpr::cmp_one_row(
const ObExpr &expr, ObDatum &res,
ObExpr **l_row, ObEvalCtx &l_ctx, ObExpr **r_row, ObEvalCtx &r_ctx)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(T_OP_SQ_NSEQ == expr.type_)) {
ret = ObExprNullSafeEqual::ns_equal(expr, res, l_row, l_ctx, r_row, r_ctx);
} else {
ret = ObRelationalExprOperator::row_cmp(expr, res, l_row, l_ctx, r_row, r_ctx);
}
return ret;
}
int ObSubQueryRelationalExpr::subquery_cmp_eval(
const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
const ExtraInfo &info = ExtraInfo::get_info(expr);
ObSubQueryIterator *l_iter = NULL;
ObSubQueryIterator *r_iter = NULL;
ObExpr **l_row = NULL;
ObExpr **r_row = NULL;
ObEvalCtx *l_ctx = NULL;
ObEvalCtx *r_ctx = NULL;
if (2 != expr.arg_cnt_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected argument count", K(ret));
} else if (OB_FAIL(setup_row(expr.args_, ctx, info.left_is_iter_, expr.inner_func_cnt_,
l_iter, l_row, l_ctx))) {
LOG_WARN("setup left row failed", K(ret));
} else if (OB_FAIL(setup_row(expr.args_ + 1, ctx, info.right_is_iter_, expr.inner_func_cnt_,
r_iter, r_row, r_ctx))) {
LOG_WARN("setup right row failed", K(ret));
} else if (OB_ISNULL(l_row) || OB_ISNULL(r_row)
|| OB_ISNULL(l_ctx) || OB_ISNULL(r_ctx)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null row", K(ret));
} else {
bool l_end = false;
if (NULL != l_iter) {
if (OB_FAIL(l_iter->get_next_row())) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
l_end = true;
// set row to NULL
for (int64_t i = 0; i < expr.inner_func_cnt_; i++) {
l_row[i]->locate_expr_datum(*l_ctx).set_null();
l_row[i]->set_evaluated_projected(*l_ctx);
}
} else {
LOG_WARN("get next row failed", K(ret));
}
}
}
if (OB_SUCC(ret)) {
switch (info.subquery_key_) {
case T_WITH_NONE: {
ret = subquery_cmp_eval_with_none(expr, *l_ctx, expr_datum, l_row, *r_ctx, r_row, r_iter);
break;
}
case T_WITH_ANY: {
ret = subquery_cmp_eval_with_any(expr, *l_ctx, expr_datum, l_row, *r_ctx, r_row, r_iter);
break;
}
case T_WITH_ALL: {
ret = subquery_cmp_eval_with_all(expr, *l_ctx, expr_datum, l_row, *r_ctx, r_row, r_iter);
break;
}
}
}
if (OB_SUCC(ret) && NULL != l_iter && !l_end) {
if (OB_FAIL(l_iter->get_next_row())) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
} else {
LOG_WARN("get next row failed", K(ret));
}
} else {
// only one row expected for left row
ret = OB_SUBQUERY_TOO_MANY_ROW;
}
}
}
return ret;
}
int ObSubQueryRelationalExpr::subquery_cmp_eval_with_none(
const ObExpr &expr, ObEvalCtx &l_ctx, ObDatum &res,
ObExpr **l_row, ObEvalCtx &r_ctx, ObExpr **r_row, ObSubQueryIterator *r_iter)
{
int ret = OB_SUCCESS;
// %l_row, %r_row is checked no need to check.
// %iter may be NULL for with none.
bool iter_end = false;
if (NULL != r_iter) {
if (OB_FAIL(r_iter->get_next_row())) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
iter_end = true;
// set row to NULL
for (int64_t i = 0; i < expr.inner_func_cnt_; i++) {
r_row[i]->locate_expr_datum(r_ctx).set_null();
r_row[i]->set_evaluated_projected(r_ctx);
}
} else {
LOG_WARN("get next row failed", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(cmp_one_row(expr, res, l_row, l_ctx, r_row, r_ctx))) {
LOG_WARN("compare one row failed", K(ret));
}
}
if (NULL != r_iter && !iter_end && OB_SUCC(ret)) {
if (OB_FAIL(r_iter->get_next_row())) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
} else {
LOG_WARN("get next row failed", K(ret));
}
} else {
// only one row expected for left row
ret = OB_SUBQUERY_TOO_MANY_ROW;
}
}
return ret;
}
// copy from ObSubQueryRelationalExpr::calc_result_with_any
int ObSubQueryRelationalExpr::subquery_cmp_eval_with_any(
const ObExpr &expr, ObEvalCtx &l_ctx, ObDatum &res,
ObExpr **l_row, ObEvalCtx &r_ctx, ObExpr **r_row, ObSubQueryIterator *r_iter)
{
// %l_row, %r_row is checked no need to check.
int ret = OB_SUCCESS;
if (OB_ISNULL(r_iter)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("iter should not be null", K(ret));
} else {
bool cnt_null = false;
//mysql和oracle的行为是如果ANY集合是空集,那么比较结果为false,所以初始化为false
res.set_false();
while (OB_SUCC(ret) && OB_SUCC(r_iter->get_next_row())) {
// use subquery's eval ctx for right row to avoid ObEvalCtx::alloc_ expanding.
if (OB_FAIL(cmp_one_row(expr, res, l_row, l_ctx, r_row, r_ctx))) {
LOG_WARN("compare single row failed", K(ret));
} else if (res.is_true()) {
break;
//只要有一个元素满足条件,结果就为true,所以跳出迭代
} else if (res.is_null()) {
cnt_null = true;
}
}
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
if (OB_SUCC(ret)) {
if (res.is_false() && cnt_null) {
res.set_null();
}
}
}
return ret;
}
// copy from ObSubQueryRelationalExpr::calc_result_with_all
int ObSubQueryRelationalExpr::subquery_cmp_eval_with_all(
const ObExpr &expr, ObEvalCtx &l_ctx, ObDatum &res,
ObExpr **l_row, ObEvalCtx &r_ctx, ObExpr **r_row, ObSubQueryIterator *r_iter)
{
// %l_row, %r_row is checked no need to check.
int ret = OB_SUCCESS;
if (OB_ISNULL(r_iter)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("iter should not be null", K(ret));
} else {
bool cnt_null = false;
//mysql和oracle的行为是如果ALL集合是空集,那么比较结果为true,所以初始化为true
res.set_true();
while (OB_SUCC(ret) && OB_SUCC(r_iter->get_next_row())) {
// use subquery's eval ctx for right row to avoid ObEvalCtx::alloc_ expanding.
if (OB_FAIL(cmp_one_row(expr, res, l_row, l_ctx, r_row, r_ctx))) {
LOG_WARN("compare single row failed", K(ret));
} else if (res.is_false()) {
break;
//只要有一个元素满足条件,结果就为true,所以跳出迭代
} else if (res.is_null()) {
cnt_null = true;
}
}
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
if (OB_SUCC(ret)) {
if (res.is_true() && cnt_null) {
res.set_null();
}
}
}
return ret;
}
int ObLogicalExprOperator::calc_result_type1(ObExprResType &type,
ObExprResType &type1,
ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
UNUSED(type1);
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
type.set_tinyint();
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
return ret;
}
int ObSubQueryRelationalExpr::calc_result_type2_(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
ObExprResType cmp_type;
if (OB_SUCC(calc_cmp_type2(cmp_type, type1, type2, type_ctx.get_coll_type()))) {
type.set_tinyint();
type.set_calc_collation(cmp_type);
type.set_calc_type(cmp_type.get_calc_type());
ObExprOperator::calc_result_flag2(type, type1, type2);
}
return ret;
}
int ObLogicalExprOperator::calc_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
UNUSED(type1);
UNUSED(type2);
UNUSED(type_ctx);
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
type.set_tinyint();
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
return ret;
}
int ObLogicalExprOperator::calc_result_type3(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprResType &type3,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
UNUSED(type1);
UNUSED(type2);
UNUSED(type3);
UNUSED(type_ctx);
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
type.set_tinyint();
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("row_dimension_ is not NOT_ROW_DIMENSION", K(ret));
}
return ret;
}
int ObLogicalExprOperator::calc_result_typeN(ObExprResType &type,
ObExprResType *types,
int64_t param_num,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
UNUSED(types);
UNUSED(param_num);
UNUSED(type_ctx);
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
type.set_tinyint();
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
return ret;
}
int ObLogicalExprOperator::is_true(const ObObj &obj, ObCastMode cast_mode, bool &result)
{
int ret = OB_SUCCESS;
if (OB_FAIL(ObObjEvaluator::is_true(obj, cast_mode, result))) {
//ugly...really ugly in order to be compatible with mysql.
if (OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD == ret) {
//slow path. need twice calls for is_true_. not efficient but we will not reach here too frequently
ret = ObObjEvaluator::is_true(obj, CM_WARN_ON_FAIL | CM_NO_RANGE_CHECK, result);
}
}
return ret;
}
int ObVectorExprOperator::calc_result_type1(ObExprResType &type,
ObExprResType &type1,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_ERR_UNEXPECTED;
UNUSED(type);
UNUSED(type1);
UNUSED(type_ctx);
LOG_WARN("operator in should not come here", K(ret));
return ret;
}
int ObVectorExprOperator::calc_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
ObArenaAllocator alloc;
ObExprResType types[2] = {alloc, alloc};
types[0] = type1;
types[1] = type2;
return calc_result_typeN(type, types, 2, type_ctx);
}
int ObVectorExprOperator::calc_result_type3(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprResType &type3,
ObExprTypeCtx &type_ctx) const
{
ObArenaAllocator alloc;
ObExprResType types[3] = {alloc, alloc, alloc};
types[0] = type1;
types[1] = type2;
types[2] = type3;
return calc_result_typeN(type, types, 3, type_ctx);
}
int ObVectorExprOperator::calc_result_typeN(ObExprResType &type,
ObExprResType *types,
int64_t param_num,
ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num <= 0 || 0 >= row_dimension_)
|| OB_ISNULL(type_ctx.get_session())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("types is null or invalid param num or row_dimension_",
K(types), K(param_num), K(row_dimension_), K(type_ctx.get_session()), K(ret));
} else {
int64_t left_start_idx = 0;
int64_t right_start_idx = row_dimension_;
int64_t right_element_count = param_num / row_dimension_ - 1;
ObExprResType tmp_res_type;
if (OB_FAIL(type.init_row_dimension(param_num))) {
LOG_WARN("fail to init row dimension", K(ret));
}
int not_composite_elem_idx = OB_INVALID_INDEX;
bool has_composite_elem = false;
// in 可能是nest table, (nt1 in (nt2, nt3, nt4))
for (int64_t k = 0; lib::is_oracle_mode() && k < param_num; ++k) {
if (!types[k].is_ext()) {
not_composite_elem_idx = k;
}
has_composite_elem |= types[k].is_ext();
}
if (lib::is_oracle_mode() && has_composite_elem) {
if (row_dimension_ != 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("in condition of nest table can only have one left operator", K(ret),
K(row_dimension_),
K(param_num));
} else if (not_composite_elem_idx != OB_INVALID_INDEX) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP,
ob_obj_type_str(types[not_composite_elem_idx].get_type()), ob_obj_type_str(ObExtendType));
} else {
// 在这儿extend type不知道具体元素的类型。需要在计算时获取。
// do nothing
}
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < right_element_count;
++i, right_start_idx += row_dimension_) {
tmp_res_type.reset();
for (int64_t j = 0; OB_SUCC(ret) && j < row_dimension_; ++j) {
if (OB_FAIL(ObVectorExprOperator::calc_result_type2_(tmp_res_type,
types[left_start_idx+ j],
types[right_start_idx + j],
type_ctx))) {
LOG_WARN("failed to calc result types", K(ret));
} else if (OB_FAIL(type.get_row_calc_cmp_types().push_back(tmp_res_type.get_calc_meta()))) {
LOG_WARN("failed to push back cmp type", K(ret));
}
}
}
}
// overall result type
if (OB_SUCC(ret)) {
type.set_int32();
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[type.get_type()].precision_);
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[type.get_type()].scale_);
ObExprOperator::calc_result_flagN(type, types, param_num);
}
}
return ret;
}
int ObVectorExprOperator::calc_result_type2_(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
ObExprResType cmp_type;
if (lib::is_oracle_mode() && (type1.is_lob()
|| type1.is_lob_locator())) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()),
ob_obj_type_str(type2.get_type()));
} else if (lib::is_oracle_mode() && (type2.is_lob()
|| type2.is_lob_locator())) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()),
ob_obj_type_str(type2.get_type()));
} else if (OB_SUCC(calc_cmp_type2(cmp_type, type1, type2, type_ctx.get_coll_type()))) {
type.set_int(); // not tinyint, compatiable with MySQL
type.set_calc_collation(cmp_type);
type.set_calc_type(cmp_type.get_calc_type());
ObExprOperator::calc_result_flag2(type, type1, type2);
bool need_no_cast = ObRelationalExprOperator::can_cmp_without_cast(type1,
type2,
CO_EQ);
type1.set_calc_type(need_no_cast ? type1.get_type() : cmp_type.get_calc_type());
type2.set_calc_type(need_no_cast ? type2.get_type() : cmp_type.get_calc_type());
if (ob_is_string_type(cmp_type.get_calc_type())) {
if (OB_ISNULL(type_ctx.get_session())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid null session", K(type_ctx.get_session()));
} else if (lib::is_oracle_mode()) {
// oracle 字符集推导
ObExprResType tmp_res_type;
ObSEArray<ObExprResType *, 2> tmp_param_array;
if (OB_FAIL(tmp_param_array.push_back(&type1))
|| OB_FAIL(tmp_param_array.push_back(&type2))) {
LOG_WARN("failed to push back element", K(ret));
} else if (OB_FAIL(aggregate_string_type_and_charset_oracle(
*type_ctx.get_session(), tmp_param_array, tmp_res_type))) {
LOG_WARN("unexpected failed", K(ret));
} else if (OB_FAIL(deduce_string_param_calc_type_and_charset(
*type_ctx.get_session(), tmp_res_type, tmp_param_array))) {
LOG_WARN("unexpected failed", K(ret));
}
} else {
type1.set_calc_collation_type(cmp_type.get_calc_collation_type());
type2.set_calc_collation_type(cmp_type.get_calc_collation_type());
}
} else if (ObRawType == cmp_type.get_calc_type()) {
type1.set_calc_collation_type(CS_TYPE_BINARY);
type2.set_calc_collation_type(CS_TYPE_BINARY);
}
}
return ret;
}
int ObStringExprOperator::convert_result_collation(const ObExprResType &result_type,
ObObj &in_obj, ObIAllocator *allocator)
{
int ret = OB_SUCCESS;
ObCollationType in_collation = in_obj.get_collation_type();
ObString out_str;
if (OB_UNLIKELY(!in_obj.is_string_or_lob_locator_type()
|| !result_type.is_string_or_lob_locator_type()
|| !ObCharset::is_valid_collation(in_collation)
|| !ObCharset::is_valid_collation(result_type.get_collation_type())
|| OB_ISNULL(allocator))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(in_obj), K(result_type));
} else if (OB_FAIL(ObExprUtil::convert_string_collation(in_obj.get_string(), in_collation,
out_str, result_type.get_collation_type(), *allocator))) {
LOG_WARN("convert_string_collation failed", K(ret), K(in_obj), K(result_type));
} else {
in_obj.set_string(result_type.get_type(), out_str);
in_obj.set_collation(result_type);
}
return ret;
}
// for calc result type and length for function date_format and time_format.
void ObStringExprOperator::calc_temporal_format_result_length(ObExprResType &type,
const ObExprResType &format) const
{
const int64_t VARCHAR_RES_MAX_PARAM_LENGTH = 17;
const int64_t TEXT_RES_MAX_PARAM_LENGTH = 728;
const int64_t MAX_VARCHAR_BUFFER_SIZE = 256;
if (ob_is_string_tc(format.get_type())) {
// consistent with Mysql, result_length / format_length = 30
const int64_t ratio = 30;
if (format.get_length() <= VARCHAR_RES_MAX_PARAM_LENGTH) {
type.set_varchar();
type.set_length(format.get_length() * ratio);
} else if (format.get_length() < TEXT_RES_MAX_PARAM_LENGTH) {
type.set_type(ObTextType);
type.set_length(OB_MAX_TEXT_LENGTH);
} else {
type.set_type(ObLongTextType);
type.set_length(OB_MAX_LONGTEXT_LENGTH);
}
} else if (ob_is_text_tc(format.get_type())) {
type.set_type(ObTinyTextType == format.get_type() ? ObTextType : ObLongTextType);
type.set_length(ObTextType == type.get_type() ? OB_MAX_TEXT_LENGTH : OB_MAX_LONGTEXT_LENGTH);
} else {
type.set_varchar();
type.set_length(MAX_VARCHAR_BUFFER_SIZE);
}
if (is_mysql_mode() && ob_is_text_tc(type.get_type())) {
const int32_t mbmaxlen = 4;
const int32_t default_text_length =
ObAccuracy::DDL_DEFAULT_ACCURACY[type.get_type()].get_length() / mbmaxlen;
// need to set a correct length for text tc in mysql mode
type.set_length(default_text_length);
}
}
ObObjType ObStringExprOperator::get_result_type_mysql(int64_t char_length) const
{
/*
drop table t1;
drop table t2;
create table t1 (
col_varchar varchar(1),
col_varbinary varbinary(1),
col_char char(1),
col_binary binary(1),
col_tinytext tinytext,
col_tinyblob tinyblob,
col_mediumtext mediumtext,
col_mediumblob mediumblob,
col_text text,
col_blob blob,
col_count bigint);
create table t2 as
select repeat('啊', 512),
repeat('a', 513),
repeat('啊', 21845),
repeat('a', 21846),
repeat(col_varchar, '512'),
repeat(col_varchar, '513'),
repeat(col_varchar, 65535),
repeat(col_varchar, 65536),
repeat(col_varbinary, '512'),
repeat(col_varbinary, '513'),
repeat(col_varbinary, 65535),
repeat(col_varbinary, 65536),
repeat(col_char, '512'),
repeat(col_char, '513'),
repeat(col_char, 65535),
repeat(col_char, 65536),
repeat(col_binary, '512'),
repeat(col_binary, '513'),
repeat(col_binary, 65535),
repeat(col_binary, 65536),
repeat(col_tinytext, 2),
repeat(col_tinytext, 3),
repeat(col_tinytext, 257),
repeat(col_tinytext, 258),
repeat(col_tinyblob, 2),
repeat(col_tinyblob, 3),
repeat(col_tinyblob, 257),
repeat(col_tinyblob, 258),
repeat(col_mediumtext, 1),
repeat(col_mediumblob, 1),
repeat(col_text, 1),
repeat(col_text, 2),
repeat(col_blob, 1),
repeat(col_blob, 2),
repeat('啊', col_count),
repeat('a', col_count),
repeat(col_varchar, col_count),
repeat(col_varbinary, col_count),
repeat(col_char, col_count),
repeat(col_binary, col_count),
repeat(col_tinytext, col_count),
repeat(col_tinyblob, col_count),
repeat(col_mediumtext, col_count),
repeat(col_mediumblob, col_count),
repeat(col_text, col_count),
repeat(col_blob, col_count)
from t1;
desc t2;
MySQL [jiuren]> desc t2;
+-----------------------------------+----------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------------------+----------------+------+-----+---------+-------+
| repeat('啊', 512) | varchar(512) | YES | | NULL | |
| repeat('a', 513) | text | YES | | NULL | |
| repeat('啊', 21845) | text | YES | | NULL | |
| repeat('a', 21846) | longtext | YES | | NULL | |
| repeat(col_varchar, '512') | varchar(512) | YES | | NULL | |
| repeat(col_varchar, '513') | text | YES | | NULL | |
| repeat(col_varchar, 65535) | text | YES | | NULL | |
| repeat(col_varchar, 65536) | longtext | YES | | NULL | |
| repeat(col_varbinary, '512') | varbinary(512) | YES | | NULL | |
| repeat(col_varbinary, '513') | blob | YES | | NULL | |
| repeat(col_varbinary, 65535) | blob | YES | | NULL | |
| repeat(col_varbinary, 65536) | longblob | YES | | NULL | |
| repeat(col_char, '512') | varchar(512) | YES | | NULL | |
| repeat(col_char, '513') | text | YES | | NULL | |
| repeat(col_char, 65535) | text | YES | | NULL | |
| repeat(col_char, 65536) | longtext | YES | | NULL | |
| repeat(col_binary, '512') | varbinary(512) | YES | | NULL | |
| repeat(col_binary, '513') | blob | YES | | NULL | |
| repeat(col_binary, 65535) | blob | YES | | NULL | |
| repeat(col_binary, 65536) | longblob | YES | | NULL | |
| repeat(col_tinytext, 2) | varchar(510) | YES | | NULL | |
| repeat(col_tinytext, 3) | text | YES | | NULL | |
| repeat(col_tinytext, 257) | text | YES | | NULL | |
| repeat(col_tinytext, 258) | longtext | YES | | NULL | |
| repeat(col_tinyblob, 2) | varbinary(510) | YES | | NULL | |
| repeat(col_tinyblob, 3) | blob | YES | | NULL | |
| repeat(col_tinyblob, 257) | blob | YES | | NULL | |
| repeat(col_tinyblob, 258) | longblob | YES | | NULL | |
| repeat(col_mediumtext, 1) | longtext | YES | | NULL | |
| repeat(col_mediumblob, 1) | longblob | YES | | NULL | |
| repeat(col_text, 1) | text | YES | | NULL | |
| repeat(col_text, 2) | longtext | YES | | NULL | |
| repeat(col_blob, 1) | blob | YES | | NULL | |
| repeat(col_blob, 2) | longblob | YES | | NULL | |
| repeat('啊', col_count) | longtext | YES | | NULL | |
| repeat('a', col_count) | longtext | YES | | NULL | |
| repeat(col_varchar, col_count) | longtext | YES | | NULL | |
| repeat(col_varbinary, col_count) | longblob | YES | | NULL | |
| repeat(col_char, col_count) | longtext | YES | | NULL | |
| repeat(col_binary, col_count) | longblob | YES | | NULL | |
| repeat(col_tinytext, col_count) | longtext | YES | | NULL | |
| repeat(col_tinyblob, col_count) | longblob | YES | | NULL | |
| repeat(col_mediumtext, col_count) | longtext | YES | | NULL | |
| repeat(col_mediumblob, col_count) | longblob | YES | | NULL | |
| repeat(col_text, col_count) | longtext | YES | | NULL | |
| repeat(col_blob, col_count) | longblob | YES | | NULL | |
+-----------------------------------+----------------+------+-----+---------+-------+
46 rows in set (0.00 sec)
* summarize the rules that mysql decide the result type of some string functions,
* which mainly depend on the MAX CHAR LENGTH of result:
* 1. less than or equal to 512: varchar, otherwise
* 2. less than or equal to 65535: text or blob, otherwise
* 3. longtext or longblob (including UNKNOWN length when count param is not const).
* do not care about the input data type, or whether the input is column or const.
*
* ATTENTION! we will ignore these exceptions:
* 1. repeat('啊', 21845) => text, repeat('a', 21846) => longtext. we can not
* understand the magic numbers 21845 and 21846.
* 2. repeat(col_mediumtext, 1) => longtext, repeat(col_mediumblob, 1) => longblob.
* text or blob is enough, see:
* repeat(col_text, 1) => text, repeat(col_blob, 1) => blob.
*/
ObObjType res_type = ObMaxType;
if (char_length <= MAX_CHAR_LENGTH_FOR_VARCAHR_RESULT) {
res_type = ObVarcharType;
} else if (char_length <= MAX_CHAR_LENGTH_FOR_TEXT_RESULT) {
res_type = ObTextType;
} else {
res_type = ObLongTextType;
}
return res_type;
}
// for static_typing_engine
int ObBitwiseExprOperator::set_calc_type(ObExprResType &type)
{
// 如果参数的结果类型是number tc,则calc type也应该是number tc
// 在实际计算时,针对number tc有round/trunc处理
// 如果参数的结果类型不是number tc,则calc type都设置为int/uint
if (lib::is_oracle_mode()) {
type.set_calc_type(ObNumberType);
type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER);
type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER);
} else {
if (ObNumberType == type.get_type()) {
type.set_calc_type(ObNumberType);
type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER);
type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER);
} else {
type.set_calc_type(ObIntType);
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObIntType].precision_);
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObIntType].scale_);
}
}
return OB_SUCCESS;
}
int ObBitwiseExprOperator::calc_result_type1(ObExprResType &type,
ObExprResType &type1,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
if (is_oracle_mode()) {
type.set_number();
type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER);
type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER);
} else {
type.set_uint64();
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_);
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].scale_);
}
ObExprOperator::calc_result_flag1(type, type1);
if (OB_FAIL(set_calc_type(type1))) {
LOG_WARN("set_calc_type for type1 failed", K(ret), K(type1));
} else {
ObCastMode cm = lib::is_oracle_mode() ? CM_NONE : CM_STRING_INTEGER_TRUNC;
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NO_RANGE_CHECK | cm);
}
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
return ret;
}
int ObBitwiseExprOperator::calc_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
if (is_oracle_mode()) {
type.set_number();
type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER);
type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER);
} else {
type.set_uint64();
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_);
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].scale_);
}
ObExprOperator::calc_result_flag2(type, type1, type2);
if (OB_FAIL(set_calc_type(type1))) {
LOG_WARN("set_calc_type for type1 failed", K(ret), K(type1));
} else if (OB_FAIL(set_calc_type(type2))) {
LOG_WARN("set_calc_type for type2 failed", K(ret), K(type2));
} else {
ObCastMode cm = lib::is_oracle_mode() ? CM_NONE : CM_STRING_INTEGER_TRUNC;
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NO_RANGE_CHECK | cm);
}
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
LOG_DEBUG("bitwise calc type2 done", K(ret), K(type), K(type1), K(type2));
return ret;
}
int ObBitwiseExprOperator::calc_result_type3(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprResType &type3,
ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
if (is_oracle_mode()) {
type.set_number();
type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER);
type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER);
} else {
type.set_uint64();
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_);
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].scale_);
}
ObExprOperator::calc_result_flag3(type, type1, type2, type3);
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("row_dimension_ is not NOT_ROW_DIMENSION", K(ret));
}
return ret;
}
int ObBitwiseExprOperator::calc_result_typeN(ObExprResType &type,
ObExprResType *types,
int64_t param_num,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
UNUSED(types);
UNUSED(param_num);
UNUSED(type_ctx);
if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
if (is_oracle_mode()) {
type.set_number();
type.set_precision(DEFAULT_NUMBER_PRECISION_FOR_INTEGER);
type.set_scale(DEFAULT_NUMBER_SCALE_FOR_INTEGER);
} else {
type.set_uint64();
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
}
ObExprOperator::calc_result_flagN(type, types, param_num);
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
return ret;
}
int ObBitwiseExprOperator::calc_(ObObj &res,
const ObObj &obj1,
const ObObj &obj2,
ObExprCtx &expr_ctx,
BitOperator op) const
{
int ret = OB_SUCCESS;
if (OB_ISNULL(expr_ctx.calc_buf_)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("expr_ctx.calc_buf_ is null", K(expr_ctx.calc_buf_), K(ret));
} else if (OB_UNLIKELY(op < 0 || op >= BIT_MAX)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid index", K(obj1), K(obj2), K(op));
} else if (OB_UNLIKELY(obj1.is_null() || obj2.is_null())) {
res.set_null();
} else {
if (lib::is_mysql_mode()) {
uint64_t uint64_v1 = 0;
uint64_t uint64_v2 = 0;
if (OB_FAIL(get_uint64(obj1, expr_ctx, true, uint64_v1))) {
LOG_WARN("fail to get uint64", K(obj1), K(ret));
} else if (OB_FAIL(get_uint64(obj2, expr_ctx, true, uint64_v2))) {
LOG_WARN("fail to get uint64", K(obj2), K(ret));
} else {
//Do not worry too much about the efficiency
//although we calc 5 results while only one is used here.
//Bit operations take little time
uint64_t bit_op_res[BIT_MAX] = { uint64_v1 & uint64_v2,
uint64_v1 | uint64_v2,
uint64_v1 ^ uint64_v2,
uint64_v2 < sizeof(uint64_t) * 8 ? uint64_v1 << uint64_v2 : 0,
uint64_v2 < sizeof(uint64_t) * 8 ? uint64_v1 >> uint64_v2 : 0};
res.set_uint64(bit_op_res[op]);
}
} else {
if (op != BIT_AND) {
ret = OB_NOT_SUPPORTED; // oracle模式仅支持bitand操作
LOG_USER_ERROR(OB_NOT_SUPPORTED, "bit op in oracle mode except bitand");
LOG_WARN("not support bit op in oracle mode", K(ret), K(op));
} else {
int64_t int64_v1 = 0;
int64_t int64_v2 = 0;
if (OB_FAIL(get_int64(obj1, expr_ctx, false, int64_v1))) {
LOG_WARN("failed to get int64", K(obj1), K(ret));
} else if (OB_FAIL(get_int64(obj2, expr_ctx, false, int64_v2))) {
LOG_WARN("failed to get int64", K(obj2), K(ret));
} else {
ObNumber result;
result.from((int64_v1 & int64_v2), *expr_ctx.calc_buf_);
res.set_number(result);
}
}
}
}
return ret;
}
int ObBitwiseExprOperator::calc_result2_mysql(const ObExpr &expr, ObEvalCtx &ctx,
ObDatum &res_datum)
{
int ret = OB_SUCCESS;
ObDatum *left = NULL;
ObDatum *right = NULL;
const BitOperator op = static_cast<const BitOperator>(expr.extra_);
ObCastMode cast_mode = CM_NONE;
if (OB_UNLIKELY(op < 0 || op >= BIT_MAX)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(op));
} else if (OB_FAIL(expr.args_[0]->eval(ctx, left))) {
LOG_WARN("eval arg 0 failed", K(ret));
} else if (left->is_null()) {
res_datum.set_null();
} else if (OB_FAIL(expr.args_[1]->eval(ctx, right))) {
LOG_WARN("eval arg 1 failed", K(ret));
} else if (right->is_null()) {
res_datum.set_null();
} else if (OB_FAIL(ObSQLUtils::get_default_cast_mode(false, 0,
ctx.exec_ctx_.get_my_session(), cast_mode))) {
LOG_WARN("get default cast mode failed", K(ret));
} else {
uint64_t left_uint = 0;
uint64_t right_uint = 0;
void *get_uint_func0 = NULL;
void *get_uint_func1 = NULL;
const ObObjType &left_type = expr.args_[0]->datum_meta_.type_;
const ObObjType &right_type = expr.args_[1]->datum_meta_.type_;
// choose_get_int_func可以想办法放到cg阶段,但是bitwise表达式
// 应该不是性能敏感的地方
if (OB_FAIL(choose_get_int_func(left_type, get_uint_func0))) {
LOG_WARN("choose_get_int_func failed", K(ret), K(left_type));
} else if (OB_FAIL((reinterpret_cast<GetUIntFunc>(get_uint_func0)(*left, true,
left_uint, cast_mode)))) {
LOG_WARN("get uint64 failed", K(ret), K(*left));
} else if (OB_FAIL(choose_get_int_func(right_type, get_uint_func1))) {
LOG_WARN("choose_get_int_func failed", K(ret), K(right_type));
} else if (OB_FAIL((reinterpret_cast<GetUIntFunc>(get_uint_func1)(*right, true,
right_uint, cast_mode)))) {
LOG_WARN("get uint64 failed", K(ret), K(*right));
} else {
//Do not worry too much about the efficiency
//although we calc 5 results while only one is used here.
//Bit operations take little time
uint64_t bit_op_res[BIT_MAX] = { left_uint & right_uint,
left_uint | right_uint,
left_uint ^ right_uint,
right_uint < sizeof(uint64_t) * 8 ?
left_uint << right_uint : 0,
right_uint < sizeof(uint64_t) * 8 ?
left_uint >> right_uint : 0};
res_datum.set_uint(bit_op_res[op]);
}
}
return ret;
}
int ObBitwiseExprOperator::calc_result2_oracle(const ObExpr &expr, ObEvalCtx &ctx,
ObDatum &res_datum)
{
int ret = OB_SUCCESS;
ObDatum *left = NULL;
ObDatum *right = NULL;
const BitOperator op = static_cast<const BitOperator>(expr.extra_);
ObCastMode cast_mode = CM_NONE;
if (OB_UNLIKELY(BIT_AND != op)) {
ret = OB_NOT_SUPPORTED; // oracle模式仅支持bitand操作
LOG_USER_ERROR(OB_NOT_SUPPORTED, "bit op in oracle mode except bitand");
LOG_WARN("unsupported bit operator", K(ret), K(op), K(BIT_AND));
} else if (OB_FAIL(expr.args_[0]->eval(ctx, left))) {
LOG_WARN("eval arg 0 failed", K(ret));
} else if (left->is_null()) {
res_datum.set_null();
} else if (OB_FAIL(expr.args_[1]->eval(ctx, right))) {
LOG_WARN("eval arg 1 failed", K(ret));
} else if (right->is_null()) {
res_datum.set_null();
} else if (OB_FAIL(ObSQLUtils::get_default_cast_mode(false, 0,
ctx.exec_ctx_.get_my_session(), cast_mode))) {
LOG_WARN("get default cast mode failed", K(ret));
} else {
int64_t left_int = 0;
int64_t right_int = 0;
ObNumStackOnceAlloc tmp_alloc;
ObNumber result;
void *get_int_func0 = NULL;
void *get_int_func1 = NULL;
const ObObjType &left_type = expr.args_[0]->datum_meta_.type_;
const ObObjType &right_type = expr.args_[1]->datum_meta_.type_;
// choose_get_int_func可以想办法放到cg阶段,但是bitwise表达式
// 应该不是性能敏感的地方
if (OB_FAIL(choose_get_int_func(left_type, get_int_func0))) {
LOG_WARN("choose_get_int_func failed", K(ret), K(left_type));
} else if (OB_FAIL((reinterpret_cast<GetIntFunc>(get_int_func0)(*left, false,
left_int, cast_mode)))) {
LOG_WARN("get uint64 failed", K(ret), K(*left));
} else if (OB_FAIL(choose_get_int_func(right_type, get_int_func1))) {
LOG_WARN("choose_get_int_func failed", K(ret), K(right_type));
} else if (OB_FAIL((reinterpret_cast<GetIntFunc>(get_int_func1)(*right, false,
right_int, cast_mode)))) {
LOG_WARN("get uint64 failed", K(ret), K(*right));
} else if (OB_FAIL(result.from((left_int & right_int), tmp_alloc))) {
LOG_WARN("get ObNumber from int64 failed", K(ret), K(left_int & right_int));
} else {
res_datum.set_number(result);
}
}
return ret;
}
// for static typing engine
int ObBitwiseExprOperator::cg_bitwise_expr(ObExprCGCtx &expr_cg_ctx,
const ObRawExpr &raw_expr,
ObExpr &rt_expr, const BitOperator op)
{
int ret = OB_SUCCESS;
UNUSED(raw_expr);
// bit count, bit neg: 1 == arg_cnt_
// bit and/or/xor/left shift/right shift: 2 == arg_cnt_
if (OB_ISNULL(rt_expr.args_) || OB_ISNULL(expr_cg_ctx.allocator_) ||
OB_UNLIKELY(1 != rt_expr.arg_cnt_ && 2 != rt_expr.arg_cnt_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("args_ is NULL or arg_cnt_ is invalid", K(ret), K(rt_expr));
} else {
rt_expr.extra_ = static_cast<uint64_t>(op);
if (2 == rt_expr.arg_cnt_) {
if (lib::is_oracle_mode()) {
rt_expr.eval_func_ = ObBitwiseExprOperator::calc_result2_oracle;
} else {
rt_expr.eval_func_ = ObBitwiseExprOperator::calc_result2_mysql;
}
} else {
// must be set in its cg_expr method
// bit_neg和bit_count有自己的计算函数
rt_expr.eval_func_ = NULL;
}
}
return ret;
}
int ObBitwiseExprOperator::choose_get_int_func(const ObObjType type, void *&out_func)
{
int ret = OB_SUCCESS;
if (ObNumberTC == ob_obj_type_class(type)) {
if (lib::is_oracle_mode()) {
out_func = reinterpret_cast<void*>(
ObBitwiseExprOperator::get_int64_from_number_type);
} else {
out_func = reinterpret_cast<void*>(
ObBitwiseExprOperator::get_uint64_from_number_type);
}
} else {
// 针对非number的输入,类型推导阶段会增加implicit cast将其转为int64/uint64
if (lib::is_oracle_mode()) {
out_func = reinterpret_cast<void*>(ObBitwiseExprOperator::get_int64_from_int_tc);
} else {
out_func = reinterpret_cast<void*>(ObBitwiseExprOperator::get_uint64_from_int_tc);
}
}
return ret;
}
int ObBitwiseExprOperator::get_int64_from_int_tc(const ObDatum &datum, bool is_round,
int64_t &out, const ObCastMode &cast_mode)
{
int ret = OB_SUCCESS;
UNUSED(is_round);
UNUSED(cast_mode);
out = datum.get_int();
return ret;
}
int ObBitwiseExprOperator::get_uint64_from_int_tc(const ObDatum &datum, bool is_round,
uint64_t &out, const ObCastMode &cast_mode)
{
int ret = OB_SUCCESS;
UNUSED(is_round);
UNUSED(cast_mode);
out = datum.get_uint();
return ret;
}
int ObBitwiseExprOperator::get_int64_from_number_type(const ObDatum &datum,
bool is_round,
int64_t &out,
const ObCastMode &cast_mode)
{
int ret = OB_SUCCESS;
int64_t tmp_int = 0;
ObNumStackAllocator<> num_allocator;
number::ObNumber nmb;
if (OB_FAIL(nmb.from(datum.get_number(), num_allocator))) {
LOG_WARN("number copy failed", K(ret));
} else if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) {
LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb));
} else if (nmb.is_valid_int64(tmp_int)) {
out = tmp_int;
} else {
ret = OB_ERR_TRUNCATED_WRONG_VALUE;
if (CM_IS_WARN_ON_FAIL(cast_mode)) {
ret = OB_SUCCESS;
out = 0;
}
}
return ret;
}
int ObBitwiseExprOperator::get_uint64_from_number_type(const ObDatum &datum,
bool is_round,
uint64_t &out,
const ObCastMode &cast_mode)
{
int ret = OB_SUCCESS;
ObNumStackAllocator<> num_allocator;
number::ObNumber nmb;
int64_t tmp_int = 0;
uint64_t tmp_uint = 0;
if (OB_FAIL(nmb.from(datum.get_number(), num_allocator))) {
LOG_WARN("number copy failed", K(ret));
} else if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) {
LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb));
} else if (nmb.is_valid_int64(tmp_int)) {
out = static_cast<uint64_t>(tmp_int);
} else if (nmb.is_valid_uint64(tmp_uint)) {
out = tmp_uint;
} else {
ret = OB_ERR_TRUNCATED_WRONG_VALUE;
if (CM_IS_WARN_ON_FAIL(cast_mode)) {
ret = OB_SUCCESS;
out = 0;
}
}
return ret;
}
int ObBitwiseExprOperator::get_int64(const ObObj &obj,
ObExprCtx &expr_ctx,
bool is_round,
int64_t &out)
{
int ret = OB_SUCCESS;
out = 0;
ObObjType type = obj.get_type();
if (OB_LIKELY(ob_is_int_tc(type))) {
out = obj.get_int();
} else if (OB_UNLIKELY(obj.is_number())) {
int64_t tmp_int = 0;
number::ObNumber nmb;
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
if (OB_FAIL(nmb.from(obj.get_number(), cast_ctx))) {
LOG_WARN("deep copy failed", K(ret), K(is_round), K(obj));
} else if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) {
LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb));
} else if (nmb.is_valid_int64(tmp_int)) {
out = tmp_int;
} else {
ret = OB_ERR_TRUNCATED_WRONG_VALUE;
if (CM_IS_WARN_ON_FAIL(cast_ctx.cast_mode_)) {
ret = OB_SUCCESS;
out = 0;
}
}
} else {
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
EXPR_GET_INT64_V2(obj, out);
}
return ret;
}
int ObBitwiseExprOperator::get_uint64(const ObObj &obj,
ObExprCtx &expr_ctx,
bool is_round,
uint64_t &out)
{
int ret = OB_SUCCESS;
out = 0;
ObObjType type = obj.get_type();
if (OB_LIKELY(ob_is_int_tc(type))) {
out = static_cast<uint64_t>(obj.get_int());
} else if (ob_is_uint_tc(type)) {
out = obj.get_uint64();
} else if (OB_UNLIKELY(obj.is_number())) {
uint64_t tmp_uint = 0;
number::ObNumber value = obj.get_number();
if (OB_LIKELY(value.is_valid_uint64(tmp_uint))) {
out = tmp_uint;
} else {
int64_t tmp_int = 0;
number::ObNumber nmb;
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
if (OB_FAIL(nmb.from(value, cast_ctx))) {
LOG_WARN("deep copy failed", K(ret), K(is_round), K(obj));
} else if (OB_UNLIKELY(!nmb.is_integer() && OB_FAIL(is_round ? nmb.round(0) : nmb.trunc(0)))) {
LOG_WARN("round/trunc failed", K(ret), K(is_round), K(nmb));
} else if (nmb.is_valid_int64(tmp_int)) {
out = static_cast<uint64_t>(tmp_int);
} else if (nmb.is_valid_uint64(tmp_uint)) {
out = tmp_uint;
} else {
ret = OB_ERR_TRUNCATED_WRONG_VALUE;
if (CM_IS_WARN_ON_FAIL(cast_ctx.cast_mode_)) {
ret = OB_SUCCESS;
out = 0;
}
}
}
} else {
// need add CM_NO_RANGE_CHECK, otherwise 1 & -3.5(float) return 0.
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NO_RANGE_CHECK);
EXPR_GET_UINT64_V2(obj, out);
}
return ret;
}
int ObMinMaxExprOperator::assign(const ObExprOperator &other)
{
int ret = OB_SUCCESS;
const ObMinMaxExprOperator *tmp_other = dynamic_cast<const ObMinMaxExprOperator *>(&other);
if (OB_UNLIKELY(NULL == tmp_other)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument. wrong type for other", K(ret), K(other));
} else if (OB_LIKELY(this != tmp_other)) {
if (OB_FAIL(ObExprOperator::assign(other))) {
LOG_WARN("copy in Base class ObExprOperator failed", K(ret));
} else {
this->need_cast_ = tmp_other->need_cast_;
}
}
return ret;
}
int ObMinMaxExprOperator::aggregate_result_type_for_comparison(ObExprResType &type,
const ObExprResType *types,
int64_t param_num) const
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else {
ObObjType res_type = types[0].get_type();
ObScale max_scale = types[0].get_scale();
for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) {
if (OB_FAIL(ObExprResultTypeUtil::get_relational_result_type(res_type,
res_type,
types[i].get_type()))) {
// warn
} else if (OB_UNLIKELY(ObMaxType == res_type)) {
ret = OB_INVALID_ARGUMENT; // not compatible input
} else if (!ob_is_string_or_lob_type(types[i].get_type()) && types[i].get_scale() > max_scale) {
max_scale = types[i].get_scale();
}
}
if (OB_SUCC(ret)) {
type.set_type(res_type);
type.set_scale(max_scale);
}
}
return ret;
}
int ObMinMaxExprOperator::aggregate_cmp_type_for_comparison(ObExprResType &type,
const ObExprResType *types,
int64_t param_num) const
{
int ret = OB_SUCCESS;
if (OB_ISNULL(types) || OB_UNLIKELY(param_num < 1)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("types is null or param_num is wrong", K(types), K(param_num), K(ret));
} else {
ObObjType cmp_type = types[0].get_type();
for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) {
if (OB_FAIL(ObExprResultTypeUtil::get_relational_cmp_type(cmp_type,
cmp_type,
types[i].get_type()))) {
// warn
} else if (OB_UNLIKELY(ObMaxType == cmp_type)) {
ret = OB_INVALID_ARGUMENT; // not compatible input
}
}
if (OB_SUCC(ret)) {
type.set_calc_type(cmp_type);
}
}
return ret;
}
int ObMinMaxExprOperator::calc_result_meta_for_comparison(
ObExprResType &type,
ObExprResType *types_stack,
int64_t param_num,
const ObCollationType coll_type,
const ObLengthSemantics default_length_semantics) const
{
UNUSED(default_length_semantics);
int ret = OB_SUCCESS;
int64_t i = 0;
//bool all_string = true;
if (OB_ISNULL(types_stack) || OB_UNLIKELY(param_num < 1)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("stack is null or param_num is wrong", K(types_stack), K(param_num), K(ret));
}
// result_type
if (OB_SUCC(ret)) {
ret = aggregate_result_type_for_comparison(type, types_stack, param_num);
}
// cmp_type
// 都是varchar,采用varchar比较,否则转成数值比较
if (OB_SUCC(ret)) {
ret = aggregate_cmp_type_for_comparison(type, types_stack, param_num);
}
bool string_result = ob_is_string_or_enumset_type(type.get_type())
|| ob_is_text_tc(type.get_type());
bool string_cmp = ob_is_string_or_enumset_type(type.get_calc_type())
|| ob_is_text_tc(type.get_calc_type());
// compare collation
if (OB_SUCC(ret) && string_cmp) {
ret = aggregate_charsets_for_comparison(type, types_stack, param_num, coll_type);
}
// result collation
if (OB_SUCC(ret) && string_result) {
ret = aggregate_charsets_for_string_result(type, types_stack, param_num, coll_type);
}
if (OB_SUCC(ret)) {
if (string_result) {
int64_t max_length = 0;
for (i = 0; i < param_num; ++i) {
max_length = MAX(max_length, types_stack[i].get_length());
}
type.set_length(static_cast<ObLength>(max_length));
} else {
int64_t max_scale = 0;
int64_t max_precision = 0;
for (i = 0; i < param_num; ++i) {
max_scale = MAX(max_scale, types_stack[i].get_mysql_compatible_scale());
max_precision = MAX(max_precision, types_stack[i].get_precision());
}
ObScale result_scale = static_cast<ObScale>(NOT_FIXED_DEC == max_scale ? -1 : max_scale);
const int64_t int32_max_precision = 11;
if (result_scale > 0 && ob_is_int_tc(type.get_type())) {
//兼容mysql行为,least(datetime/time/timestamp,int)结果类型为int
//least(datetime(3)/time(3)/timestamp(3),int)结果类型为decimal。
type.set_type(ObNumberType);
} else if (max_precision > int32_max_precision && ObInt32Type == type.get_type()) {
//兼容mysql行为对类型进行提升。
type.set_type(ObIntType);
}
type.set_scale(result_scale);
type.set_precision(static_cast<ObPrecision>(max_precision + max_scale)); // esti, not accurate
}
}
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*/}
}
return ret;
}
int ObMinMaxExprOperator::calc_(ObObj &result,
const ObObj *objs_stack,
int64_t param_num,
const ObExprResType &result_type,
ObExprCtx &expr_ctx,
ObCmpOp cmp_op,
bool need_cast)
{
// todo(jiuren):
// we assume that result type / result collation / compare type / compare collation are CORRECT.
// but who knowns? we should check it ASAP.
int ret = OB_SUCCESS;
if (OB_UNLIKELY(need_cast)) {
ret = calc_with_cast(result, objs_stack, param_num, result_type, expr_ctx, cmp_op);
} else {
ret = calc_without_cast(result, objs_stack, param_num, result_type, expr_ctx, cmp_op);
}
return ret;
}
int ObMinMaxExprOperator::calc_without_cast(ObObj &result,
const ObObj *objs_stack,
int64_t param_num,
const ObExprResType &result_type,
ObExprCtx &expr_ctx,
ObCmpOp cmp_op)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(CO_LT != cmp_op && CO_GT != cmp_op)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("the compare oper is wrong", K(ret), K(cmp_op));
} else if (OB_ISNULL(objs_stack)
|| OB_ISNULL(expr_ctx.calc_buf_)
|| OB_UNLIKELY(param_num < 1)
|| OB_UNLIKELY(result_type.is_invalid())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("stack is null or param_num is wrong", K(objs_stack), K(param_num), K(result_type), K(ret));
} else {
bool has_null = false;
for (int i = 0; OB_SUCC(ret) && !has_null && i < param_num; ++i) {
if (objs_stack[i].is_null()) {
has_null = true;
result.set_null();
}
}
if (!has_null) {
// compare all params.
int res_idx = 0;
ObCollationType cmp_cs_type = result_type.get_calc_collation_type();
for (int i = 1; OB_SUCC(ret) && i < param_num; ++i) {
if (ObObjCmpFuncs::compare_oper_nullsafe(objs_stack[i], objs_stack[res_idx], cmp_cs_type, cmp_op)) {
res_idx = i;
}
}
// ok, we got the least / greatest param.
if (OB_SUCC(ret)) {
if (OB_LIKELY(result_type.get_type() == objs_stack[res_idx].get_type()
&& result_type.get_collation_type() == objs_stack[res_idx].get_collation_type())) {
result = objs_stack[res_idx];
} else { //slow path
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
if (OB_FAIL(ObObjCaster::to_type(result_type.get_type(), result_type.get_collation_type(),
cast_ctx, objs_stack[res_idx], result))) {
}
}
}
}
}
return ret;
}
int ObMinMaxExprOperator::calc_with_cast(ObObj &result,
const ObObj *objs_stack,
int64_t param_num,
const ObExprResType &result_type,
ObExprCtx &expr_ctx,
ObCmpOp cmp_op)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(CO_LT != cmp_op && CO_GT != cmp_op)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("the compare oper is wrong", K(ret), K(cmp_op));
} else if (OB_ISNULL(objs_stack)
|| OB_ISNULL(expr_ctx.calc_buf_)
|| OB_UNLIKELY(param_num < 1)
|| OB_UNLIKELY(result_type.is_invalid())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("stack is null or param_num is wrong", K(objs_stack), K(param_num), K(result_type), K(ret));
} else {
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
if (ob_is_nstring_type(result_type.get_calc_type())) {
cast_ctx.dest_collation_ = expr_ctx.my_session_->get_nls_collation_nation();
} else if (lib::is_mysql_mode() && ob_is_json(result_type.get_calc_type())) {
cast_ctx.dest_collation_ = CS_TYPE_UTF8MB4_BIN;
} //for https://work.aone.alibaba-inc.com/issue/30742303 类型不一致导致挂住
else if (lib::is_mysql_mode() && CS_TYPE_INVALID != result_type.get_collation_type()) {
cast_ctx.dest_collation_ = result_type.get_collation_type();
}
ObFixedArray<ObObj, ObIAllocator> buf_obj(expr_ctx.calc_buf_, param_num);
ObFixedArray<const ObObj*, ObIAllocator> res_obj(expr_ctx.calc_buf_, param_num);// inited in the for loop below.
if (OB_FAIL(buf_obj.prepare_allocate(param_num))) {
LOG_WARN("prepare allocate failed", K(param_num), K(ret));
} else if (OB_FAIL(res_obj.prepare_allocate(param_num))) {
LOG_WARN("prepare allocate failed", K(param_num), K(ret));
}
//ret status will be checked within OB_SUCC(ret)s
bool has_null = false;
// cast all params to cmp type, and check if exist null.
for (int i = 0; OB_SUCC(ret) && !has_null && i < param_num; ++i) {
res_obj[i] = NULL;
if (objs_stack[i].is_null()) {
has_null = true;
result.set_null();
} else if (OB_FAIL(ObObjCaster::to_type(result_type.get_calc_type(), cast_ctx,
objs_stack[i], buf_obj[i], res_obj[i]))) {
} else if (OB_ISNULL(res_obj[i])) {
ret = OB_ERR_UNEXPECTED;
}
}
if (OB_SUCC(ret) && !has_null) {
// compare all params.
int res_idx = 0;
ObCollationType cmp_cs_type = result_type.get_calc_collation_type();
for (int i = 1; OB_SUCC(ret) && i < param_num; ++i) {
if (ObObjCmpFuncs::compare_oper_nullsafe(*res_obj[i], *res_obj[res_idx], cmp_cs_type, cmp_op)) {
res_idx = i;
}
}
// ok, we got the least / greatest param.
if (OB_SUCC(ret)) {
if (OB_FAIL(ObObjCaster::to_type(result_type.get_type(), result_type.get_collation_type(),
cast_ctx, objs_stack[res_idx], result))) {
}
}
}
}
return ret;
}
int ObArithExprOperator::interval_add_minus(ObObj &res, const ObObj &left, const ObObj &right,
ObExprCtx &expr_ctx, ObScale scale, bool is_minus)
{
return interval_add_minus(res, left, right, get_timezone_info(expr_ctx.my_session_), scale, is_minus);
}
int ObArithExprOperator::interval_add_minus(ObObj &res, const ObObj &left, const ObObj &right,
const ObTimeZoneInfo *time_zone, ObScale scale, bool is_minus)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(ObIntervalTC != right.get_type_class())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else {
switch (left.get_type_class()) {
case ObIntervalTC: { //interval + interval
if (OB_UNLIKELY(left.get_type() != right.get_type())) {
ret = OB_ERR_INVALID_TYPE_FOR_OP; //ORA-30081: invalid data type for datetime/interval arithmetic
LOG_WARN("invalid data type interval arithmetic");
} else if (left.is_interval_ym()) {
ObIntervalYMValue value = is_minus ? left.get_interval_ym() - right.get_interval_ym()
: left.get_interval_ym() + right.get_interval_ym();
if (OB_FAIL(value.validate())) {
LOG_WARN("value validate failed", K(ret), K(value));
} else {
res.set_interval_ym(value);
res.set_scale(ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][ObIntervalYMType].get_scale());
}
LOG_DEBUG("add interval year to month result", K(value), K(res));
} else {
ObIntervalDSValue value = is_minus ? left.get_interval_ds() - right.get_interval_ds()
: left.get_interval_ds() + right.get_interval_ds();
if (OB_FAIL(value.validate())) {
LOG_WARN("value validate failed", K(ret), K(value));
} else {
res.set_interval_ds(value);
res.set_scale(ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][ObIntervalDSType].get_scale());
}
LOG_DEBUG("add interval day to second result", K(value), K(res));
}
break;
}
case ObDateTimeTC: { //date +- interval
int64_t date_v = left.get_datetime();
int64_t result_v = 0;
int64_t sign = is_minus ? -1 : 1;
if (OB_FAIL(right.is_interval_ym() ?
ObTimeConverter::date_add_nmonth(date_v,
right.get_interval_ym().get_nmonth() * sign,
result_v)
: ObTimeConverter::date_add_nsecond(date_v,
right.get_interval_ds().get_nsecond()* sign,
right.get_interval_ds().get_fs() * sign,
result_v))) {
LOG_WARN("add value failed", K(ret), K(left), K(right));
} else {
res.set_datetime(result_v);
res.set_scale(0);
}
break;
}
case ObOTimestampTC: { //timestamp +- interval
ObOTimestampData result_v;
int32_t sign = is_minus ? -1 : 1;
if (OB_FAIL(right.is_interval_ym() ?
ObTimeConverter::otimestamp_add_nmonth(left.get_type(),
left.get_otimestamp_value(),
time_zone,
right.get_interval_ym().get_nmonth() * sign,
result_v)
: ObTimeConverter::otimestamp_add_nsecond(left.get_otimestamp_value(),
right.get_interval_ds().get_nsecond() * sign,
right.get_interval_ds().get_fs() * sign,
result_v))) {
LOG_WARN("calc with timestamp value failed", K(ret), K(left), K(right));
} else {
res.set_otimestamp_value(left.get_type(), result_v);
res.set_scale(MAX_SCALE_FOR_ORACLE_TEMPORAL);
}
break;
}
case ObNullTC: {
res.set_null();
break;
}
default: {
ret = OB_ERR_INVALID_TYPE_FOR_OP; //ORA-30081: invalid data type for datetime/interval arithmetic
LOG_WARN("invalid calc type", K(ret));
}
}
}
LOG_DEBUG("add interval", K(left), K(right), K(scale), K(res));
UNUSED(scale);
return ret;
}
int ObMinMaxExprOperator::deserialize(const char *buf, const int64_t data_len, int64_t &pos)
{
int ret = OB_SUCCESS;
need_cast_ = true;//defensive code
if (OB_FAIL(ObExprOperator::deserialize(buf, data_len, pos))) {
LOG_WARN("deserialize in BASE class failed", K(ret));
} else {
OB_UNIS_DECODE(need_cast_);
}
return ret;
}
int ObMinMaxExprOperator::serialize(char *buf, const int64_t buf_len, int64_t &pos) const
{
int ret = OB_SUCCESS;
if (OB_FAIL(ObExprOperator::serialize(buf, buf_len, pos))) {
LOG_WARN("serialize in BASE class failed", K(ret));
} else {
OB_UNIS_ENCODE(need_cast_);
}
return ret;
}
int64_t ObMinMaxExprOperator::get_serialize_size() const
{
int64_t len = 0;
BASE_ADD_LEN((ObMinMaxExprOperator, ObExprOperator));
OB_UNIS_ADD_LEN(need_cast_);
return len;
}
//ObLocationExprOperator
int ObLocationExprOperator::calc_result_type2(ObExprResType &type,
ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
ObExprOperator::calc_result_flag2(type, type1, type2);
type.set_int();
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObIntType].precision_);
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
type1.set_calc_type(ObVarcharType);
type2.set_calc_type(ObVarcharType);
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC);
ObObjMeta types[2] = {type1, type2};
OZ(aggregate_charsets_for_comparison(type.get_calc_meta(), types, 2, type_ctx.get_coll_type()));
OX(type1.set_calc_collation_type(type.get_calc_collation_type()));
OX(type2.set_calc_collation_type(type.get_calc_collation_type()));
return ret;
}
int ObLocationExprOperator::calc_result2(common::ObObj &result,
const common::ObObj &obj1,
const common::ObObj &obj2,
common::ObExprCtx &expr_ctx) const
{
ObObj position;
position.set_int(1);
return ObLocationExprOperator::calc_result3(result, obj1, obj2, position, expr_ctx);
}
int ObLocationExprOperator::calc_result3(common::ObObj &result,
const common::ObObj &obj1,
const common::ObObj &obj2,
const common::ObObj &obj3,
ObExprCtx &expr_ctx) const
{
int ret = OB_SUCCESS;
if (OB_ISNULL(expr_ctx.calc_buf_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("the pointer is null", K(expr_ctx.calc_buf_), K(ret));
} else if (OB_UNLIKELY(obj1.is_null() || obj2.is_null())) {
result.set_null();
} else if (obj3.is_null()) {
result.set_int(0);
} else if (OB_UNLIKELY(!is_type_valid(obj1.get_type())
|| !is_type_valid(obj2.get_type())
|| !is_type_valid(obj3.get_type()))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("the param is not castable", K(obj1), K(obj2), K(obj3), K(ret));
} else {
int64_t pos = 0;
ret = get_pos_int64(obj3, expr_ctx, pos);
if (OB_SUCC(ret)) {
TYPE_CHECK(obj1, ObVarcharType);
TYPE_CHECK(obj2, ObVarcharType);
ObString str1 = obj1.get_string();
ObString str2 = obj2.get_string();
uint32_t idx = ObCharset::locate(result_type_.get_calc_collation_type(),
str2.ptr(),
str2.length(),
str1.ptr(),
str1.length(),
pos);
result.set_int(static_cast<int64_t>(idx));
}
}
return ret;
}
int ObLocationExprOperator::get_pos_int64(const ObObj &obj, ObExprCtx &expr_ctx, int64_t &out)
{
int ret = OB_SUCCESS;
out = 0;
ObObjType type = obj.get_type();
if (OB_LIKELY(ob_is_int_tc(type))) {
out = obj.get_int();
} else if (ob_is_uint_tc(type)) {
uint64_t value = obj.get_uint64();
out = (value > INT64_MAX) ? 0 : static_cast<int64_t>(value);
} else if (OB_UNLIKELY(obj.is_number())) {
int64_t tmp_int = 0;
uint64_t tmp_uint = 0;
number::ObNumber nmb = obj.get_number();
number::ObNumber *pnmb = &nmb;
number::ObNumber newmb;
if (OB_UNLIKELY(!nmb.is_integer())) {
//such as select locate('bar', 'foobarbar', 5.3); yeah, really ugly.
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
if (OB_FAIL(newmb.from(nmb, cast_ctx))) { //copy is essential since if we did not do that, obj will be modified
LOG_WARN("copy nmb failed", K(ret), K(nmb));
} else if (OB_FAIL(newmb.round(0))) {
LOG_WARN("round failed", K(ret), K(nmb));
} else {
pnmb = &newmb;
}
}
if (OB_FAIL(ret)) {
//do nothing
} else if (OB_ISNULL(pnmb)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected error. null pointer", K(ret));
} else if (pnmb->is_valid_int64(tmp_int)) {
out = tmp_int;
} else if (pnmb->is_valid_uint64(tmp_uint)) {
out = 0;//no errors no warnings in mysql.
} else {
ret = OB_ERR_TRUNCATED_WRONG_VALUE;
if (CM_IS_WARN_ON_FAIL(expr_ctx.cast_mode_)) {
ret = OB_SUCCESS;
out = 0;
}
}
} else {
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
EXPR_GET_INT64_V2(obj, out);
}
return ret;
}
// location相关的表达式的第一个和第二个参数在计算前,cs_type要设定为一样的,否则
// ObCharset::locate()无法确定使用哪个cs_type进行计算
int ObLocationExprOperator::get_calc_cs_type(const ObExpr &expr, ObCollationType &calc_cs_type)
{
int ret = OB_SUCCESS;
const ObCollationType cs_type1 = expr.args_[0]->datum_meta_.cs_type_;
const ObCollationType cs_type2 = expr.args_[1]->datum_meta_.cs_type_;
if (OB_UNLIKELY(cs_type1 != cs_type2)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cs type should be same", K(ret), K(cs_type1), K(cs_type2));
} else if (OB_UNLIKELY(!ObCharset::is_valid_collation(static_cast<int64_t>(cs_type1)))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid cs_type", K(ret), K(cs_type1));
} else {
calc_cs_type = cs_type1;
}
return ret;
}
int ObLocationExprOperator::calc_location_expr(const ObExpr &expr, ObEvalCtx &ctx,
ObDatum &res_datum)
{
int ret = OB_SUCCESS;
// locate(sub, ori, pos)
if (OB_UNLIKELY(2 > expr.arg_cnt_ || 3 < expr.arg_cnt_) || OB_ISNULL(expr.args_) ||
OB_ISNULL(expr.args_[0]) || OB_ISNULL(expr.args_[1])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid expr", K(ret), K(expr));
} else if (OB_FAIL(calc_(expr, *expr.args_[0], *expr.args_[1], ctx, res_datum))) {
LOG_WARN("calc_ faied", K(ret));
}
return ret;
}
// instr和locate的参数顺序正好相反,所以需要抽出这个函数
// eg: locate(sub_str, ori_str): 待搜索的子串是第一个参数
// instr(ori_str, sub_str): 待搜索的子串时第二个参数
int ObLocationExprOperator::calc_(const ObExpr &expr, const ObExpr &sub_arg,
const ObExpr &ori_arg, ObEvalCtx &ctx,
ObDatum &res_datum)
{
int ret = OB_SUCCESS;
ObDatum *sub = NULL;
ObDatum *ori = NULL;
ObDatum *pos = NULL;
bool has_result = false;
// 第一个和第二个参数有null时不会短路,第三个参数才会短路
if (OB_FAIL(sub_arg.eval(ctx, sub)) || OB_FAIL(ori_arg.eval(ctx, ori))) {
LOG_WARN("eval arg failed", K(ret));
} else if (sub->is_null() || ori->is_null()) {
res_datum.set_null();
has_result = true;
}
int64_t pos_int = 1;
if (OB_SUCC(ret) && !has_result && 3 == expr.arg_cnt_) {
if (OB_FAIL(expr.args_[2]->eval(ctx, pos))) {
LOG_WARN("eval arg 2 failed", K(ret));
} else if (pos->is_null()) {
res_datum.set_int(0);
has_result = true;
} else {
// TODO: 验证MySQL下uint64超过int64值域范围,隐式cast的结果
// https://aone.alibaba-inc.com/req/25068696
pos_int = pos->get_int();
}
}
if (OB_SUCC(ret) && !has_result) {
const ObString &ori_str = ori->get_string();
const ObString &sub_str = sub->get_string();
ObCollationType calc_cs_type = CS_TYPE_INVALID;
if (OB_FAIL(get_calc_cs_type(expr, calc_cs_type))) {
LOG_WARN("get_calc_cs_type failed", K(ret));
} else {
uint32_t idx = ObCharset::locate(calc_cs_type, ori_str.ptr(), ori_str.length(),
sub_str.ptr(), sub_str.length(), pos_int);
res_datum.set_int(static_cast<int64_t>(idx));
}
}
return ret;
}
int ObLocationExprOperator::cg_expr(ObExprCGCtx &op_cg_ctx, const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
UNUSED(op_cg_ctx);
UNUSED(raw_expr);
rt_expr.eval_func_ = calc_location_expr;
return OB_SUCCESS;
}
int ObExprTRDateFormat::calc_hash(const char *p, int64_t len, uint64_t &hash)
{
int ret = OB_SUCCESS;
hash = 0;
if (OB_ISNULL(p) || OB_UNLIKELY(len <= 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected error.invalid arguments", K(p), K(len));
} else {
for(int64_t i = 0; i < len; ++i) {
hash = (hash << 7) + (hash << 1) + hash + toupper(p[i]);
}
}
return ret;
}
int ObExprTRDateFormat::init()
{
int ret = OB_SUCCESS;
for (int64_t i = 0; i < FORMAT_MAX_TYPE && OB_SUCC(ret); ++i) {
ret = calc_hash(FORMATS_TEXT[i], strlen(FORMATS_TEXT[i]), FORMATS_HASH[i]);
//validation
for (int64_t j = 0; j < i && OB_SUCC(ret); ++j) {
if (FORMATS_HASH[i] == FORMATS_HASH[j]) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected error.hash func is not perfect hash", K(i), K(j));
break;
}
}
}
return ret;
}
int ObExprTRDateFormat::get_format_id_by_format_string(const ObString &fmt, int64_t &fmt_id)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(fmt.empty())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("empty string.", K(ret), K(fmt));
} else {
fmt_id = SYYYY;
const char *ptr = fmt.ptr();
int32_t ptr_len = fmt.length();
uint64_t fmt_hash = 0;
if (OB_FAIL(calc_hash(ptr, ptr_len, fmt_hash))) {
LOG_WARN("calc hash failed", K(ret), K(fmt));
} else if (FALSE_IT(get_format_id(fmt_hash, fmt_id))) {
} else if (OB_UNLIKELY(fmt_id < 0 || fmt_id >= FORMAT_MAX_TYPE)) {
ret = OB_INVALID_DATE_FORMAT;
LOG_WARN("invalid format string", K(ret), K(fmt_id), K(fmt));
} else if (OB_UNLIKELY(strncasecmp(ptr, FORMATS_TEXT[fmt_id], ptr_len))) {
//what a pity ! same hash value, while not expected content
ret = OB_INVALID_DATE_FORMAT;
LOG_WARN("invalid format string", K(ret), K(fmt_id), K(fmt));
}
}
return ret;
}
int ObExprTRDateFormat::trunc_new_obtime(ObTime &ob_time, const ObString &fmt)
{
int ret = OB_SUCCESS;
int64_t fmt_id = SYYYY;
OZ (get_format_id_by_format_string(fmt, fmt_id));
OZ (trunc_new_obtime_by_fmt_id(ob_time, fmt_id));
LOG_DEBUG("check value", K(ob_time), K(fmt_id), K(fmt));
return ret;
}
int ObExprTRDateFormat::trunc_new_obtime_by_fmt_id(ObTime &ob_time, int64_t fmt_id)
{
int ret = OB_SUCCESS;
switch (fmt_id) {
case SYYYY:
//go through
case YYYY:
//go through
case YEAR:
case SYEAR:
//go through
case YYY:
//go through
case YY:
//go through
case Y: {
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_YDAY] - 1);
ob_time.parts_[DT_DATE] -= offset;
break;
}
case Q: {
set_time_part_to_zero(ob_time);
int32_t quarter = (ob_time.parts_[DT_MON] + 2) / MONS_PER_QUAR;
ob_time.parts_[DT_MON] = (quarter - 1) * MONS_PER_QUAR + 1;
ob_time.parts_[DT_MDAY] = 1;
ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
break;
}
case MONTH:
//go through
case MON:
//go through
case MM:
//go through
case RM: {
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_MDAY] - 1);
ob_time.parts_[DT_DATE] -= offset;
break;
}
case WW: {
//01-01 is the first day of year
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] -= offset;
break;
}
case IW: {
//within a week. monday is the first day
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] -= offset;
break;
}
case W: {
//xx-01 is the first day
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] -= offset;
break;
}
case DDD:
//go through
case DD:
//go through
case J: {
set_time_part_to_zero(ob_time);
break;
}
case DAY:
//go through
case DY:
//go through
case D: {
//within a week. sunday is the first day
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_WDAY]) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] -= offset;
break;
}
case HH:
//go through
case HH12:
//go through
case HH24: {
ob_time.parts_[DT_MIN] = 0;
ob_time.parts_[DT_SEC] = 0;
ob_time.parts_[DT_USEC] = 0;
break;
}
case MI: {
ob_time.parts_[DT_SEC] = 0;
ob_time.parts_[DT_USEC] = 0;
break;
}
case CC:
//go through
case SCC: {
set_time_part_to_zero(ob_time);
ob_time.parts_[DT_YEAR] = ob_time.parts_[DT_YEAR] / YEARS_PER_CENTURY * YEARS_PER_CENTURY + 1;
ob_time.parts_[DT_MON] = 1;
ob_time.parts_[DT_MDAY] = 1;
ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
break;
}
case IYYY:
//go through
case IY:
//go through
case I: {
//not used heavily. so, do not care too much about performance !
set_time_part_to_zero(ob_time);
ObTimeConverter::get_first_day_of_isoyear(ob_time);
break;
}
default: {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected fmt_id", K(fmt_id), K(ret));
}
}//end switch
return ret;
}
int ObExprTRDateFormat::round_new_obtime(ObTime &ob_time, const ObString &fmt)
{
int ret = OB_SUCCESS;
int64_t fmt_id = SYYYY;
OZ (get_format_id_by_format_string(fmt, fmt_id));
OZ (round_new_obtime_by_fmt_id(ob_time, fmt_id));
LOG_DEBUG("check value", K(ob_time), K(fmt_id), K(fmt));
return ret;
}
int ObExprTRDateFormat::round_new_obtime_by_fmt_id(ObTime &ob_time, int64_t fmt_id)
{
int ret = OB_SUCCESS;
switch (fmt_id) {
case SYYYY:
//go through
case YYYY:
//go through
case YEAR:
case SYEAR:
//go through
case YYY:
//go through
case YY:
//go through
case Y: {
//>6
const int32_t add_year = (ob_time.parts_[DT_MON] > DT_PART_MAX[DT_MON] / 2) ? 1 : 0;
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_YDAY] - 1);
ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_year * DAYS_PER_YEAR[IS_LEAP_YEAR(ob_time.parts_[DT_YEAR])];
break;
}
case Q: {
//>15
const int32_t add_quarter = (((ob_time.parts_[DT_MON] - 1) % MONS_PER_QUAR > 1)
|| (1 == (ob_time.parts_[DT_MON] - 1) % MONS_PER_QUAR
&& ob_time.parts_[DT_MDAY] > DT_PART_MAX[DT_MDAY] / 2))
? 1
: 0;
set_time_part_to_zero(ob_time);
int32_t quarter = (ob_time.parts_[DT_MON] + 2) / MONS_PER_QUAR + add_quarter;
ob_time.parts_[DT_MON] = (quarter - 1) * MONS_PER_QUAR + 1;
if (ob_time.parts_[DT_MON] > DT_PART_MAX[DT_MON]) {
ob_time.parts_[DT_MON] -= static_cast<int32_t>(DT_PART_MAX[DT_MON]);
ob_time.parts_[DT_YEAR] += 1;
}
ob_time.parts_[DT_MDAY] = 1;
ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
break;
}
case MONTH:
//go through
case MON:
//go through
case MM:
//go through
case RM: {
//>15
const int32_t add_month = (ob_time.parts_[DT_MDAY] > DT_PART_MAX[DT_MDAY] / 2) ? 1 : 0;
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_MDAY] - 1);
ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_month * DAYS_PER_MON[IS_LEAP_YEAR(ob_time.parts_[DT_YEAR])][ob_time.parts_[DT_MON]];
break;
}
case WW: {
//01-01 is the first day of year
const int32_t add_ww = ((((ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2)
|| (((ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2
&& ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2))
? 1
: 0;
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_YDAY] - 1) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_ww * DAYS_PER_WEEK;
break;
}
case IW: {
//within a week. monday is the first day
const int32_t add_iw = ((((ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2)
|| (((ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2
&& ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2))
? 1
: 0;
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_WDAY] - 1) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_iw * DAYS_PER_WEEK;
break;
}
case W: {
//xx-01 is the first day
const int32_t add_w = ((((ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2)
|| (((ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2
&& ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2))
? 1
: 0;
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_MDAY] - 1) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_w * DAYS_PER_WEEK;
break;
}
case DDD:
//go through
case DD:
//go through
case J: {
const int32_t add_d = (ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2) ? 1 : 0;
set_time_part_to_zero(ob_time);
ob_time.parts_[DT_DATE] += add_d;
break;
}
case DAY:
//go through
case DY:
//go through
case D: {
//within a week. sunday is the first day
const int32_t add_dy = (((ob_time.parts_[DT_WDAY] % DAYS_PER_WEEK) > DAYS_PER_WEEK / 2)
|| ((ob_time.parts_[DT_WDAY] % DAYS_PER_WEEK) == DAYS_PER_WEEK / 2
&& ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR] / 2))
? 1
: 0;
set_time_part_to_zero(ob_time);
int32_t offset = (ob_time.parts_[DT_WDAY]) % DAYS_PER_WEEK;
ob_time.parts_[DT_DATE] = ob_time.parts_[DT_DATE] - offset + add_dy * DAYS_PER_WEEK;
break;
}
case HH:
//go through
case HH12:
//go through
case HH24: {
const int32_t add_dh = (ob_time.parts_[DT_MIN] > DT_PART_MAX[DT_MIN] / 2) ? 1 : 0;
ob_time.parts_[DT_MIN] = 0;
ob_time.parts_[DT_SEC] = 0;
ob_time.parts_[DT_USEC] = 0;
ob_time.parts_[DT_HOUR] += add_dh;
if (ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR]) {
ob_time.parts_[DT_HOUR] -= static_cast<int32_t>(DT_PART_MAX[DT_HOUR]);
ob_time.parts_[DT_DATE] += 1;
}
break;
}
case MI: {
const int32_t add_mi = (ob_time.parts_[DT_SEC] >= DT_PART_MAX[DT_SEC] / 2) ? 1 : 0;
ob_time.parts_[DT_SEC] = 0;
ob_time.parts_[DT_USEC] = 0;
ob_time.parts_[DT_MIN] += add_mi;
if (ob_time.parts_[DT_MIN] > DT_PART_MAX[DT_MIN]) {
ob_time.parts_[DT_MIN] -= static_cast<int32_t>(DT_PART_MAX[DT_MIN]);
ob_time.parts_[DT_HOUR] += 1;
if (ob_time.parts_[DT_HOUR] > DT_PART_MAX[DT_HOUR]) {
ob_time.parts_[DT_HOUR] -= static_cast<int32_t>(DT_PART_MAX[DT_HOUR]);
ob_time.parts_[DT_DATE] += 1;
}
}
break;
}
case CC:
//go through
case SCC: {
const int32_t add_cc = (ob_time.parts_[DT_YEAR] % YEARS_PER_CENTURY > YEARS_PER_CENTURY / 2) ? 1 : 0;
set_time_part_to_zero(ob_time);
ob_time.parts_[DT_YEAR] = ob_time.parts_[DT_YEAR] / YEARS_PER_CENTURY * YEARS_PER_CENTURY + 1 + add_cc * YEARS_PER_CENTURY;
ob_time.parts_[DT_MON] = 1;
ob_time.parts_[DT_MDAY] = 1;
ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
break;
}
case IYYY:
//go through
case IY:
//go through
case I: {
//not used heavily. so, do not care too much about performance !
set_time_part_to_zero(ob_time);
ret = ObTimeConverter::get_round_day_of_isoyear(ob_time);
break;
}
default: {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected fmt_id", K(fmt_id), K(ret));
}
}//end switch
return ret;
}
int ObRelationalExprOperator::is_row_cmp(const ObRawExpr &raw_expr,
int &row_dim)
{
int ret = OB_SUCCESS;
row_dim = -1;
if (OB_UNLIKELY(2 != raw_expr.get_param_count()))
{
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid param count", K(ret), K(raw_expr.get_param_count()));
} else if (T_OP_ROW == raw_expr.get_param_expr(0)->get_expr_type()
&& T_OP_ROW == raw_expr.get_param_expr(1)->get_expr_type()) {
if (raw_expr.get_param_expr(0)->get_param_count()
!= raw_expr.get_param_expr(1)->get_param_count()) {
if (1 == raw_expr.get_param_expr(1)->get_param_count()
&& T_OP_ROW == raw_expr.get_param_expr(1)->get_param_expr(0)->get_expr_type()) {
// (c1, c2) = (c1, c2), (c1, c2) = ((c1, c2)) are both allowed in oralce mode
if (raw_expr.get_param_expr(0)->get_param_count()
== raw_expr.get_param_expr(1)->get_param_expr(0)->get_param_count()) {
row_dim = raw_expr.get_param_expr(0)->get_param_count();
}
}
} else {
row_dim = raw_expr.get_param_expr(0)->get_param_count();
}
if (OB_UNLIKELY(-1 == row_dim)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected param cnt", K(raw_expr.get_param_expr(0)->get_param_count()),
K(raw_expr.get_param_expr(1)->get_param_count()),
K(raw_expr.get_param_expr(1)->get_expr_type()));
}
}
return ret;
}
int ObRelationalExprOperator::cg_expr(ObExprCGCtx &op_cg_ctx,
const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
int ret = OB_SUCCESS;
int row_dim = -1;
if (OB_FAIL(is_row_cmp(raw_expr, row_dim))) {
LOG_WARN("failed to get row dimension", K(ret));
} else if (OB_ISNULL(op_cg_ctx.allocator_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid null allocator", K(ret), K(op_cg_ctx.allocator_));
} else if (row_dim > 0) {
ret = cg_row_cmp_expr(row_dim, *op_cg_ctx.allocator_, raw_expr, input_types_,rt_expr);
} else {
ret = cg_datum_cmp_expr(raw_expr, input_types_, rt_expr);
}
return ret;
}
int ObRelationalExprOperator::cg_datum_cmp_expr(const ObRawExpr &raw_expr,
const ObExprOperatorInputTypeArray &input_types,
ObExpr &rt_expr)
{
int ret = OB_SUCCESS;
UNUSED(raw_expr);
if (OB_UNLIKELY(2 != rt_expr.arg_cnt_
|| NULL == rt_expr.args_
|| NULL == rt_expr.args_[0]
|| NULL == rt_expr.args_[1]
|| input_types.count() != 2)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else if (lib::is_oracle_mode()
&& (rt_expr.args_[0]->obj_meta_.is_ext()
|| rt_expr.args_[1]->obj_meta_.is_ext())) {
const auto &l = rt_expr.args_[0]->obj_meta_;
const auto &r = rt_expr.args_[1]->obj_meta_;
if (!(l.is_null() || l.is_ext())
|| !(r.is_null() || r.is_ext())) {
ret = OB_ERR_UNEXPECTED;
} else {
rt_expr.eval_func_ = &eval_pl_udt_compare;
LOG_WARN("unexpected type", K(ret), K(l), K(r));
}
} else {
rt_expr.inner_func_cnt_ = 0;
rt_expr.inner_functions_ = NULL;
const ObCmpOp cmp_op = get_cmp_op(raw_expr.get_expr_type());
const ObObjType input_type1 = rt_expr.args_[0]->datum_meta_.type_;
const ObObjType input_type2 = rt_expr.args_[1]->datum_meta_.type_;
LOG_DEBUG("CG Datum CMP Expr", K(input_type1), K(input_type2), K(cmp_op));
const ObCollationType cs_type = rt_expr.args_[0]->datum_meta_.cs_type_;
if (ObDatumFuncs::is_string_type(input_type1) && ObDatumFuncs::is_string_type(input_type2)) {
CK(rt_expr.args_[0]->datum_meta_.cs_type_ == rt_expr.args_[1]->datum_meta_.cs_type_);
}
if (OB_SUCC(ret)) {
rt_expr.eval_func_ = ObExprCmpFuncsHelper::get_eval_expr_cmp_func(
input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type);
rt_expr.eval_batch_func_ = ObExprCmpFuncsHelper::get_eval_batch_expr_cmp_func(
input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type);
}
CK(NULL != rt_expr.eval_func_);
CK(NULL != rt_expr.eval_batch_func_);
}
return ret;
}
int ObRelationalExprOperator::cg_row_cmp_expr(const int row_dimension,
ObIAllocator &allocator,
const ObRawExpr &raw_expr,
const ObExprOperatorInputTypeArray &input_types,
ObExpr &rt_expr)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(rt_expr.arg_cnt_ != 2
|| row_dimension <= 0
|| NULL == rt_expr.args_
|| NULL == rt_expr.args_[0]
|| NULL == rt_expr.args_[1]
|| rt_expr.args_[0]->arg_cnt_ != row_dimension
|| input_types.count() != row_dimension * 2)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else {
void **inner_func_buf = NULL;
if (OB_ISNULL(inner_func_buf = (void **)allocator.alloc(
sizeof(void *) * row_dimension))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
} else {
rt_expr.inner_func_cnt_ = row_dimension;
rt_expr.inner_functions_ = inner_func_buf;
const ObCmpOp cmp_op = get_cmp_op(raw_expr.get_expr_type());
ObExpr *left_row = rt_expr.args_[0];
ObExpr *right_row = NULL;
if (OB_LIKELY(T_OP_ROW == rt_expr.args_[1]->type_ && NULL != rt_expr.args_[1]->args_[0])) {
if (T_OP_ROW == rt_expr.args_[1]->args_[0]->type_) {
right_row = rt_expr.args_[1]->args_[0];
} else {
right_row = rt_expr.args_[1];
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected error", K(ret));
}
if (OB_ISNULL(right_row) || OB_ISNULL(left_row)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("right_row or left_row is null ptr", K(ret), K(right_row), K(left_row));
} else if (OB_UNLIKELY(left_row->arg_cnt_ != right_row->arg_cnt_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected row cnt", K(left_row->arg_cnt_), K(right_row->arg_cnt_));
}
LOG_DEBUG("CG ROW CMP Expr", K(input_types), K(cmp_op));
for (int i = 0; OB_SUCC(ret) && i < row_dimension; i++)
{
const ObObjType type1 = left_row->args_[i]->datum_meta_.type_;
const ObObjType type2 = right_row->args_[i]->datum_meta_.type_;
const ObCollationType cs_type = left_row->args_[i]->datum_meta_.cs_type_;
if (ObDatumFuncs::is_string_type(type1) && ObDatumFuncs::is_string_type(type2)) {
CK(left_row->args_[i]->datum_meta_.cs_type_
== right_row->args_[i]->datum_meta_.cs_type_);
rt_expr.inner_functions_[i] = (void*)ObExprCmpFuncsHelper::get_datum_expr_cmp_func(
type1, type2,
lib::is_oracle_mode(),
cs_type);
} else {
rt_expr.inner_functions_[i] = (void *)ObExprCmpFuncsHelper::get_datum_expr_cmp_func(
type1, type2, lib::is_oracle_mode(), cs_type);
if (OB_ISNULL(rt_expr.inner_functions_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null function", K(ret), K(i), K(type1), K(type2));
}
}
} // for end
if (OB_SUCC(ret)) {
rt_expr.eval_func_ = &row_eval;
}
}
}
return ret;
}
int ObRelationalExprOperator::row_eval(
const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(2 != expr.arg_cnt_
|| NULL == expr.args_
|| expr.inner_func_cnt_ <= 0
|| expr.args_[0]->arg_cnt_ != expr.inner_func_cnt_
|| NULL == expr.args_[0]->args_
|| NULL == expr.args_[1]->args_
|| NULL == expr.inner_functions_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else {
ObExpr *left_row = expr.args_[0];
ObExpr *right_row = NULL;
if (1 == expr.args_[1]->arg_cnt_ && T_OP_ROW == expr.args_[1]->args_[0]->type_) {
if (expr.args_[1]->args_[0]->arg_cnt_ != expr.inner_func_cnt_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected arg cnt", K(ret), K(expr.inner_func_cnt_),
K(expr.args_[1]->args_[0]->arg_cnt_));
} else {
right_row = expr.args_[1]->args_[0];
}
} else if (OB_UNLIKELY(expr.inner_func_cnt_ != expr.args_[1]->arg_cnt_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected arg cnt", K(ret), K(expr.inner_func_cnt_), K(expr.args_[1]->arg_cnt_));
} else {
right_row = expr.args_[1];
}
ret = row_cmp(expr, expr_datum, left_row->args_, ctx, right_row->args_, ctx);
}
return ret;
}
int ObRelationalExprOperator::row_cmp(
const ObExpr &expr, ObDatum &expr_datum,
ObExpr **l_row, ObEvalCtx &l_ctx, ObExpr **r_row, ObEvalCtx &r_ctx)
{
// performance critical, do not check pointer validity.
int ret = OB_SUCCESS;
ObDatum *left = NULL;
ObDatum *right = NULL;
bool cnt_row_null = false;
int first_nonequal_cmp_ret = 0;
int i = 0;
// locate first non-equal pair
for (; OB_SUCC(ret) && i < expr.inner_func_cnt_; i++) {
if (OB_FAIL(l_row[i]->eval(l_ctx, left))) {
LOG_WARN("failed to eval left in row cmp", K(ret));
} else if (left->is_null()) {
cnt_row_null = true;
} else if (OB_FAIL(r_row[i]->eval(r_ctx, right))) {
LOG_WARN("failed to eval right in row cmp", K(ret));
} else if (right->is_null()) {
cnt_row_null = true;
} else if (0 != (first_nonequal_cmp_ret = ((DatumCmpFunc)expr.inner_functions_[i])(*left, *right))) {
break;
}
} // for end
ObCmpOp cmp_op = get_cmp_op(expr.type_);
if (OB_FAIL(ret)) {
// do nothing
} else if (i == expr.inner_func_cnt_) {
if (cnt_row_null) {
expr_datum.set_null();
} else {
expr_datum.set_int(is_expected_cmp_ret(cmp_op, 0));
}
} else {
if (cnt_row_null) {
if (CO_NE == cmp_op) {
expr_datum.set_int(true);
} else if (CO_EQ == cmp_op) {
expr_datum.set_int(false);
} else {
expr_datum.set_null();
}
} else {
expr_datum.set_int(
is_expected_cmp_ret(cmp_op, first_nonequal_cmp_ret));
}
}
return ret;
}
void *ObInplaceAllocator::alloc(const int64_t size)
{
void *mem = NULL;
int ret = OB_SUCCESS;
if (NULL == alloc_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("prepare is needed", K(ret));
} else {
if (size < len_) {
mem = mem_;
} else {
alloc_->free(mem_);
len_ = next_pow2(size);
mem_ = alloc_->alloc(len_);
if (NULL == mem_) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory failed", K(ret));
} else {
mem = mem_;
alloc_ = NULL; // make sure allocate once for every prepare.
}
}
}
return mem;
}
int ObExprKMPSearchCtx::init(const ObString &pattern, const bool reverse, ObIAllocator &alloc)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(pattern.length() <= 0 || OB_ISNULL(pattern.ptr()))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid param pattern", K(ret), K(pattern));
} else if (OB_LIKELY(inited_ && is_reverse_ == reverse && pattern_ == pattern)) {
// reuse next array, do nothing
} else {
inited_ = false; // reset inited_ to false
pattern_allocator_.prepare(alloc);
next_allocator_.prepare(alloc);
char *pattern_save = static_cast<char *>(pattern_allocator_.alloc(pattern.length()));
if (OB_ISNULL(pattern_save)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate pattern memory failed", K(ret));
} else if (OB_ISNULL(next_ = static_cast<int32_t *>(next_allocator_.alloc(pattern.length() * sizeof(int32_t))))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate next memory failed", K(ret));
} else if (!reverse && OB_FAIL(ObExprUtil::kmp_next(pattern.ptr(), pattern.length(), next_))) {
LOG_WARN("fail to init kmp next array", K(ret));
} else if (reverse && OB_FAIL(ObExprUtil::kmp_next_reverse(pattern.ptr(), pattern.length(), next_))) {
LOG_WARN("fail to init kmp next reverse array", K(ret));
} else {
MEMCPY(pattern_save, pattern.ptr(), pattern.length());
pattern_.assign_ptr(pattern_save, pattern.length());
is_reverse_ = reverse;
inited_ = true;
}
}
return ret;
}
int ObExprKMPSearchCtx::substring_index_search(const ObString &text,
const int64_t count,
ObString &result)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not inited", K(ret), K(this));
} else if (0 != count) {
int64_t pos = -1;
if (0 < count) {
if (OB_FAIL(ObExprUtil::kmp(const_cast<char *>(pattern_.ptr()),
pattern_.length(),
const_cast<char *>(text.ptr()),
text.length(),
count,
next_,
pos))) {
LOG_WARN("ObExprKMPSearchCtx kmp failed", K(ret));
} else if (-1 < pos) {
// nth delim found from front to back
result.assign(const_cast<char *>(text.ptr()), static_cast<int32_t>(pos));
}
} else if (0 > count) {
if (OB_FAIL(ObExprUtil::kmp_reverse(const_cast<char *>(pattern_.ptr()),
pattern_.length(),
const_cast<char *>(text.ptr()),
text.length(),
count,
next_,
pos))) {
LOG_WARN("ObExprKMPSearchCtx kmp failed", K(ret));
} else if (-1 < pos) {
// nth delim found from back to front
result.assign(
const_cast<char *>(text.ptr() + static_cast<int32_t>(pos + pattern_.length())),
static_cast<int32_t>(text.length() - pattern_.length() - pos));
}
}
if (-1 == pos) {
// substring not found, return text
result.assign(const_cast<char *>(text.ptr()), static_cast<int32_t>(text.length()));
}
}
return ret;
}
int ObExprKMPSearchCtx::instrb_search(const ObString &haystack,
int64_t start,
int64_t occ,
int64_t &ret_idx)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not inited", K(ret), K(this));
} else if (OB_ISNULL(haystack.ptr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ptr is null", K(haystack));
} else if (haystack.length() < pattern_.length()) {
ret_idx = 0;
} else {
if (0 < start) {
// start > 0时,从start位置开始往后搜索
// 用户使用时,start是从1开始计数
// kmp没有找到子串时,ret_idx会为-1
start = start - 1;
if (start > haystack.length() || start + pattern_.length() > haystack.length()) {
ret_idx = 0;
} else if (OB_FAIL(ObExprUtil::kmp(pattern_.ptr(), pattern_.length(),
haystack.ptr() + start, haystack.length() - start, occ, next_, ret_idx))) {
LOG_WARN("ObExprKMPSearchCtx kmp failed", K(occ), K(start), K(pattern_), K(haystack));
} else if (-1 < ret_idx) {
ret_idx = ret_idx + 1 + start;
} else {
ret_idx = 0;
}
} else { // start < 0
// start < 0, 会从start位置开始往前搜索
// kmp_reverse函数要求occ为负数,否则结果为0。
// kmp_reverse没有找到子串时,ret_idx会为-1
occ = -occ;
int64_t compare_len = min(haystack.length(),
haystack.length() + start + pattern_.length());
if ((-start) > haystack.length()) {
ret_idx = 0;
} else {
if (OB_FAIL(ObExprUtil::kmp_reverse(pattern_.ptr(), pattern_.length(),
haystack.ptr(), compare_len, occ, next_,
ret_idx))) {
LOG_WARN("ObExprKMPSearchCtx kmp_reverse failed", K(occ), K(compare_len),
K(pattern_), K(haystack));
} else if (-1 < ret_idx) {
ret_idx = ret_idx + 1;
} else {
ret_idx = 0;
}
}
}
}
return ret;
}
int ObExprKMPSearchCtx::get_kmp_ctx_from_exec_ctx(ObExecContext &exec_ctx,
const uint64_t op_id,
ObExprKMPSearchCtx *&kmp_ctx)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(kmp_ctx = static_cast<ObExprKMPSearchCtx*>(exec_ctx.get_expr_op_ctx(op_id)))) {
if (OB_FAIL(exec_ctx.create_expr_op_ctx(op_id, kmp_ctx))) {
LOG_WARN("failed to create operator ctx", K(ret), K(op_id));
}
}
return ret;
}
}
}