Files
oceanbase/src/sql/engine/expr/ob_expr_operator.cpp
oceanbase-admin cea7de1475 init push
2021-05-31 22:56:52 +08:00

4866 lines
187 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"
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::ObString* get_nls_formats(const ObSQLSessionInfo* session)
{
return GET_NLS_FORMATS(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;
}
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 = STATIC_ENG_NOT_IMPLEMENT;
LOG_INFO("not implemented in sql static typing engine, "
"will retry the old engine automatically",
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;
// virtual member function pointer is vtable absolute offset + 1 (to avoid null)
const int64_t func_idx = (func_val.val_ - 1) / 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_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 {
/* type collatino convertion rules:
* 1.set target collation in cast_ctx.utf8mb4 is the default value
* 2.if both src and dest type are ObStirngTC, rule:
* a.if calc_collation is set, use it
* b.if calc_collation not set, use src 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 (share::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);
}
}
}
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;
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_ ||
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 {
// convert param types only if src and dest are different types
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);
}
} 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));
}
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;
}
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 (share::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 () 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;
}
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;
}
int ObExprOperator::aggregate_string_type_and_charset_oracle(const ObBasicSessionInfo& session,
const ObIArray<ObExprResType*>& params, ObExprResType& result, bool prefer_var_len_char)
{
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()) {
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 {
has_varying_len_string_type = true;
}
}
}
// 1. deduce type + charset
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 || prefer_var_len_char ? ObNVarchar2Type : ObNCharType;
result_charset = session.get_nls_collation_nation();
} else {
result_type = has_varying_len_string_type || 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)) {
result.set_lob_inrow();
}
result.set_collation_type(result_charset);
result.set_collation_level(CS_LEVEL_IMPLICIT);
}
//. deduce length sematics
ObLengthSemantics result_ls = LS_INVALIED;
if (OB_SUCC(ret)) {
if (result.is_nstring() || result.is_clob() || result.is_clob_locator()) {
result_ls = LS_CHAR;
} 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_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);
}
LOG_DEBUG("aggregate string charset", K(result), K(params));
return ret;
}
int ObExprOperator::deduce_string_param_calc_type_and_charset(
const ObBasicSessionInfo& session, const ObExprResType& result, ObIArray<ObExprResType*>& params)
{
UNUSED(session);
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); ++i) {
ObExprResType* param_meta = params.at(i);
CK(OB_NOT_NULL(param_meta));
OX(param_meta->set_calc_meta(result));
}
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());
}
}
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)
{
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];
for (int64_t i = 1; OB_SUCC(ret) && i < param_num; ++i) {
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))) {
LOG_WARN("fail to aggregate result type", K(ret));
}
}
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)
{
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_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))) {
} 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);
}
}
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)
{
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 {
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)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected scale.", K(ret), K(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())) {
/*
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())) {
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;
}
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;
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 (session.use_static_typing_engine()) {
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());
} 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);
}
} else {
obj_cmp_func cmp_func = NULL;
need_no_cast = ObObjCmpFuncs::can_cmp_without_cast(type1, type2, cmp_op, cmp_func);
}
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 use item_cmp_type to calc target compare type
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: 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) {
// only support <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(type1), K(type2));
}
}
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;
}
// for sqrt, ln, e functions
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 (!share::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());
ObExprOperator::calc_result_flag1(type, type1);
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 (!share::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
{
return deduce_cmp_type(*this, type, type1, type2, type_ctx);
}
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());
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():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 {
// () MySQL deal with (a,b) = (c, d) policy:
// compare pair by pair, with different types
// select (1, '1.000000') = ('1.00x', '1.000000');
// 1 compare with '1.00x' as int,
// '1.00000' compare with '1.000000' as string
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_type();
ObObjType type13 = cmp_type13.get_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;
const ObLengthSemantics default_ls = my_session.get_actual_nls_length_semantics();
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_type() == cmp_type13.get_type() && cmp_type13.get_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:: raw
// bool need_cast = (share::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()) {
// compatiable with MySQL,relational op result type is 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;
}
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;
}
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) && !type_ctx.get_session()->use_static_typing_engine()) {
// static typing engine not enabled, keep the old behavior:
// type1, type2 are unchanged
if (OB_FAIL(calc_result_type2_(tmp_res_type, type1, type2, type_ctx))) {
LOG_WARN("failed to calc_result_type2_", 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 {
type.set_tinyint();
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObTinyIntType].scale_);
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObTinyIntType].precision_);
ObExprOperator::calc_result_flag2(type, type1, type2);
}
}
if (OB_SUCC(ret) && type_ctx.get_session()->use_static_typing_engine()) {
// 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) && !type_ctx.get_session()->use_static_typing_engine()) {
// static typing engine not enabled, keep the old behavior unchanged:
// parameters' type is unchanged.
// select (c1, c2) = (select b1, b2 from B);
// c1 compare with b1 with type X,
// c2 compare with b2 with type Y
ObExprResType tmp_res_type;
for (int64_t i = 0; OB_SUCC(ret) && i < row_dimension_; ++i) {
if (OB_FAIL(ObSubQueryRelationalExpr::calc_result_type2_(
tmp_res_type, types[i], types[i + row_dimension_], type_ctx))) {
LOG_WARN("fail to calc_result_type2_ when calc_result_typeN", 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_tinyint();
ObExprOperator::calc_result_flagN(type, types, param_num);
}
}
if (OB_SUCC(ret) && type_ctx.get_session()->use_static_typing_engine()) {
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
{
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_) {
// vector compare. scenario: both left right sides are subqueries
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;
} 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 {
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;
} 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 {
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;
} else {
LOG_WARN("get next row from iter failed", K(ret));
}
} else {
ret = OB_SUBQUERY_TOO_MANY_ROW;
}
}
return ret;
}
/**
* ALL sematics: all true return true. if any false exists, return false
* if NULL exists, return NULL if other values are true, return false if any values is false
*/
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 {
tmp_result.set_bool(true); // empty set returns 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()) {
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 sematics: return true if any value is true.
* return NULL if all other values are false
* return false if all values are false
*/
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 {
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;
} 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))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL subquery ref info returned", K(ret));
} else if (OB_FAIL(ObExprSubQueryRef::get_subquery_iter(
ctx, ObExprSubQueryRef::ExtraInfo::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->start())) {
LOG_WARN("start iterate failed", K(ret));
} 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;
}
return ret;
}
int ObSubQueryRelationalExpr::setup_row(ObExpr** expr, ObEvalCtx& ctx, const bool is_iter, const int64_t cmp_func_cnt,
ObSubQueryIterator*& iter, ObExpr**& row)
{
int ret = OB_SUCCESS;
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::ExtraInfo::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->start())) {
LOG_WARN("start iterate failed", K(ret));
} else {
row = &const_cast<ExprFixedArray&>(iter->get_output()).at(0);
}
} 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;
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))) {
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))) {
LOG_WARN("setup right row failed", K(ret));
} else if (OB_ISNULL(l_row) || OB_ISNULL(r_row)) {
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(ctx).set_null();
l_row[i]->get_eval_info(ctx).evaluated_ = true;
}
} 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, ctx, expr_datum, l_row, r_row, r_iter);
break;
}
case T_WITH_ANY: {
ret = subquery_cmp_eval_with_any(expr, ctx, expr_datum, l_row, r_row, r_iter);
break;
}
case T_WITH_ALL: {
ret = subquery_cmp_eval_with_all(expr, ctx, expr_datum, l_row, 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& ctx, ObDatum& res, ObExpr** l_row, 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(ctx).set_null();
r_row[i]->get_eval_info(ctx).evaluated_ = true;
}
} else {
LOG_WARN("get next row failed", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(cmp_one_row(expr, res, l_row, ctx, r_row, 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& ctx, ObDatum& res, ObExpr** l_row, 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;
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, ctx, r_row, r_iter->get_op().get_eval_ctx()))) {
LOG_WARN("compare single row failed", K(ret));
} else if (res.is_true()) {
break;
} 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& ctx, ObDatum& res, ObExpr** l_row, 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;
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, ctx, r_row, r_iter->get_op().get_eval_ctx()))) {
LOG_WARN("compare single row failed", K(ret));
} else if (res.is_false()) {
break;
} 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_NOT_SUPPORTED;
}
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));
}
bool is_nested_table_elem = true;
// in maybe nest table, (nt1 in (nt2, nt3, nt4))
for (int64_t k = 0; lib::is_oracle_mode() && k < param_num; ++k) {
is_nested_table_elem &= types[k].is_ext();
}
if (lib::is_oracle_mode() && is_nested_table_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 {
// extend type is unknown yet, get at runtime
}
} 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 (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);
if (GCONF.enable_static_engine_for_query()) {
obj_cmp_func func_ptr = NULL;
bool need_no_cast = ObRelationalExprOperator::can_cmp_without_cast(type1, type2, CO_EQ, func_ptr);
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 (share::is_oracle_mode()) {
// oracle charset deduce
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;
}
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> 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)
{
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(ObUInt64Type);
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].precision_);
type.set_scale(ObAccuracy::DDL_DEFAULT_ACCURACY[ObUInt64Type].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);
const ObSQLSessionInfo* session = dynamic_cast<const ObSQLSessionInfo*>(type_ctx.get_session());
if (OB_ISNULL(session)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cast basic session to sql session failed", K(ret));
} else if (session->use_static_typing_engine()) {
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);
const ObSQLSessionInfo* session = dynamic_cast<const ObSQLSessionInfo*>(type_ctx.get_session());
if (OB_ISNULL(session)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cast basic session to sql session failed", K(ret));
} else if (session->use_static_typing_engine()) {
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_NOT_SUPPORTED;
}
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 (share::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 mode support bitand op only
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_;
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;
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_;
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
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 {
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;
number::ObNumber nmb(datum.get_number());
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;
number::ObNumber nmb(datum.get_number());
int64_t tmp_int = 0;
uint64_t tmp_uint = 0;
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;
int64_t byte_semantics_str_num = 0;
int64_t char_semantics_str_num = 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);
}
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())) {
type.set_type(ObNumberType);
} else if (max_precision > int32_max_precision && ObInt32Type == type.get_type()) {
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:
// 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 (share::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, *res_obj[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)
{
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(),
get_timezone_info(expr_ctx.my_session_),
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;
}
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;
}
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;
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 {
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::trunc_new_obtime(ObTime& ob_time, const ObString& fmt)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(fmt.empty())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("empty string.", K(ret), K(fmt));
} else {
int64_t 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));
} else {
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), K(fmt));
}
} // end switch
}
}
return ret;
}
int ObExprTRDateFormat::round_new_obtime(ObTime& ob_time, const ObString& fmt)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(fmt.empty())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("empty string.", K(ret), K(fmt));
} else {
int64_t 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));
} else {
LOG_DEBUG("check value", K(ob_time), K(fmt_id), K(fmt));
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), K(fmt));
}
} // 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 {
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_);
rt_expr.eval_func_ = ObExprCmpFuncsHelper::get_eval_expr_cmp_func(
input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type);
} else {
rt_expr.eval_func_ = ObExprCmpFuncsHelper::get_eval_expr_cmp_func(
input_type1, input_type2, cmp_op, lib::is_oracle_mode(), cs_type);
CK(NULL != rt_expr.eval_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_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;
}
} // namespace sql
} // namespace oceanbase