patch 4.0
This commit is contained in:
@ -13,6 +13,7 @@
|
||||
#define USING_LOG_PREFIX SQL_ENG
|
||||
|
||||
#include "sql/engine/expr/ob_expr_least.h"
|
||||
#include "sql/engine/expr/ob_expr_greatest.h"
|
||||
#include "sql/engine/expr/ob_expr_operator.h"
|
||||
#include "sql/engine/expr/ob_expr_less_than.h"
|
||||
//#include "sql/engine/expr/ob_expr_promotion_util.h"
|
||||
@ -20,23 +21,45 @@
|
||||
#include "sql/session/ob_sql_session_info.h"
|
||||
#include "lib/oblog/ob_log.h"
|
||||
#include "share/object/ob_obj_cast.h"
|
||||
#include "sql/engine/expr/ob_datum_cast.h"
|
||||
|
||||
namespace oceanbase {
|
||||
namespace oceanbase
|
||||
{
|
||||
using namespace common;
|
||||
namespace sql {
|
||||
namespace sql
|
||||
{
|
||||
|
||||
ObExprBaseLeastGreatest::ObExprBaseLeastGreatest(
|
||||
ObIAllocator& alloc, ObExprOperatorType type, const char* name, int32_t param_num)
|
||||
: ObMinMaxExprOperator(alloc, type, name, param_num, NOT_ROW_DIMENSION)
|
||||
{}
|
||||
ObExprBaseLeastGreatest::~ObExprBaseLeastGreatest()
|
||||
{}
|
||||
ObExprLeastGreatest::ObExprLeastGreatest(ObIAllocator &alloc, ObExprOperatorType type,
|
||||
const char *name, int32_t param_num)
|
||||
: ObMinMaxExprOperator(alloc,
|
||||
type,
|
||||
name,
|
||||
param_num,
|
||||
NOT_ROW_DIMENSION)
|
||||
{
|
||||
}
|
||||
|
||||
int ObExprBaseLeastGreatest::calc_result_typeN_oracle(
|
||||
ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const
|
||||
int ObExprLeastGreatest::calc_result_typeN(ObExprResType &type,
|
||||
ObExprResType *types_stack,
|
||||
int64_t param_num,
|
||||
ObExprTypeCtx &type_ctx) const
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObSQLSessionInfo* session = static_cast<const ObSQLSessionInfo*>(type_ctx.get_session());
|
||||
if (is_oracle_mode()) {
|
||||
ret = calc_result_typeN_oracle(type, types_stack, param_num, type_ctx);
|
||||
} else {
|
||||
ret = calc_result_typeN_mysql(type, types_stack, param_num, type_ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObExprLeastGreatest::calc_result_typeN_oracle(ObExprResType &type,
|
||||
ObExprResType *types,
|
||||
int64_t param_num,
|
||||
ObExprTypeCtx &type_ctx) const
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObSQLSessionInfo *session = static_cast<const ObSQLSessionInfo*>(type_ctx.get_session());
|
||||
ObExprOperator::calc_result_flagN(type, types, param_num);
|
||||
if (OB_ISNULL(session)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
@ -45,67 +68,127 @@ int ObExprBaseLeastGreatest::calc_result_typeN_oracle(
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("types is null or param_num is wrong", K(types), K(param_num), K(ret));
|
||||
} else {
|
||||
ObExprResType& first_type = types[0];
|
||||
ObExprResType &first_type = types[0];
|
||||
type = first_type;
|
||||
if (ObIntTC == first_type.get_type_class() || ObUIntTC == first_type.get_type_class() ||
|
||||
ObNumberTC == first_type.get_type_class()) {
|
||||
ObObjTypeClass first_type_class = first_type.get_type_class();
|
||||
/**
|
||||
* number类型和其它类型行为不一致,单独处理
|
||||
*/
|
||||
if (ObIntTC == first_type_class
|
||||
|| ObUIntTC == first_type_class
|
||||
|| ObNumberTC == first_type_class) {
|
||||
type.set_type(ObNumberType);
|
||||
type.set_calc_type(ObNumberType);
|
||||
// scale和precision信息设置为unknown,兼容oracle的number行为
|
||||
type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET);
|
||||
type.set_precision(PRECISION_UNKNOWN_YET);
|
||||
} else if (ObLongTextType == type.get_type()) {
|
||||
ret = OB_ERR_INVALID_TYPE_FOR_OP;
|
||||
LOG_WARN("lob type parameter not expected", K(ret));
|
||||
} else if (ObStringTC == first_type_class) {
|
||||
// https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/GREATEST.html
|
||||
if (ob_is_nstring(first_type.get_type())) {
|
||||
type.set_type(ObNVarchar2Type);
|
||||
type.set_calc_type(ObNVarchar2Type);
|
||||
} else {
|
||||
type.set_type(ObVarcharType);
|
||||
type.set_calc_type(ObVarcharType);
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* 除去number类型,经过测试,结果的scale和第一个参数的scale一样,所以
|
||||
* 这里不重新设置
|
||||
*/
|
||||
type.set_type(first_type.get_type());
|
||||
type.set_calc_type(first_type.get_type());
|
||||
}
|
||||
|
||||
if (ObStringTC == type.get_type_class()) {
|
||||
/* 只有结果是字符串需要考虑结果的length信息,经过测试,有两种情况:
|
||||
* TODO 1,如果所有参数都是常量,那么length和对应结果参数的length相同,
|
||||
* 这一块还未相好如何实现
|
||||
* 2,如果含有列,那么长度是所有参数的最大值
|
||||
* 对于结果参数需要长度是char还是byte,还需要做特殊处理
|
||||
*/
|
||||
|
||||
if (ObStringTC == type.get_type_class() || ObRawTC == type.get_type_class()) {
|
||||
int64_t max_length = 0;
|
||||
int64_t all_char = 0;
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < param_num; i++) {
|
||||
int64_t item_length = 0;
|
||||
if (ObStringTC == types[i].get_type_class() || ObLongTextType == types[i].get_type()) {
|
||||
item_length = types[i].get_length();
|
||||
if (LS_CHAR == types[i].get_length_semantics()) {
|
||||
item_length = item_length * 4;
|
||||
all_char++;
|
||||
for(int64_t i =0; OB_SUCC(ret) && i < param_num; i++) {
|
||||
int64_t item_length =0;
|
||||
switch(types[i].get_type_class()) {
|
||||
case ObStringTC:{
|
||||
item_length = types[i].get_length();
|
||||
if (LS_CHAR == types[i].get_length_semantics()) {
|
||||
item_length = item_length * 4;
|
||||
all_char++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ObTextTC:
|
||||
case ObRowIDTC: {
|
||||
item_length = types[i].get_length();
|
||||
break;
|
||||
}
|
||||
case ObRawTC: {
|
||||
// raw类型长度乘2
|
||||
item_length = types[i].get_length() * 2;
|
||||
break;
|
||||
}
|
||||
case ObNumberTC:
|
||||
case ObIntTC:
|
||||
case ObUIntTC: {
|
||||
// 处理number长度的问题,oracle最大设置成40即可,OB因为没有科学计数法,
|
||||
// 所以长度可能超过40,需要做特殊处理
|
||||
item_length = number::ObNumber::MAX_PRECISION - number::ObNumber::MIN_SCALE;
|
||||
break;
|
||||
}
|
||||
case ObFloatTC:
|
||||
case ObDoubleTC:
|
||||
case ObNullTC:
|
||||
case ObIntervalTC: {
|
||||
item_length = 40;
|
||||
break;
|
||||
}
|
||||
case ObOTimestampTC:
|
||||
case ObDateTimeTC: {
|
||||
item_length = OB_MAX_TIMESTAMP_TZ_LENGTH;
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
// all types in oracle mode have been handled
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("invalid argument", K(ret), K(types[i]), K(types[i]));
|
||||
}
|
||||
} else if (ObNumberTC == types[i].get_type_class() || ObIntTC == types[i].get_type_class() ||
|
||||
ObUIntTC == types[i].get_type_class()) {
|
||||
item_length = number::ObNumber::MAX_PRECISION - number::ObNumber::MIN_SCALE;
|
||||
} else if (ObOTimestampTC == types[i].get_type_class() || ObFloatTC == types[i].get_type_class() ||
|
||||
ObDoubleTC == types[i].get_type_class() || ObNullTC == types[i].get_type_class()) {
|
||||
item_length = 40;
|
||||
} else if (ObDateTimeTC == types[i].get_type_class()) {
|
||||
item_length = 19;
|
||||
} else {
|
||||
ret = OB_NOT_SUPPORTED;
|
||||
LOG_WARN("unsupported type", K(ret), K(types[i]), K(types[i].get_type_class()));
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
max_length = MAX(max_length, item_length);
|
||||
max_length = MAX(max_length, item_length);
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
if (all_char == param_num) {
|
||||
type.set_length(static_cast<ObLength>(max_length / 4));
|
||||
type.set_length_semantics(LS_CHAR);
|
||||
} else if (ObRawTC == type.get_type_class()) {
|
||||
type.set_length(static_cast<ObLength>(max_length / 2));
|
||||
} else {
|
||||
type.set_length(static_cast<ObLength>(max_length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在calc_result_type就开始做类型检查,和Oracle行为兼容
|
||||
if (ObNullType != types[0].get_type()) {
|
||||
for (int64_t i = 1; OB_SUCC(ret) && i < param_num; i++) {
|
||||
OZ(ObObjCaster::can_cast_in_oracle_mode(types[0].get_type_class(), types[i].get_type_class()));
|
||||
OZ(ObObjCaster::can_cast_in_oracle_mode(types[0].get_type(), types[0].get_collation_type(),
|
||||
types[i].get_type(), types[i].get_collation_type()));
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret) && session->use_static_typing_engine()) {
|
||||
//老执行引擎在类型推导时不为参数设置calc_type, 在执行期再对参数进行cast。
|
||||
//新执行引擎需要在类型推导阶段为参数设置好calc_type, 在执行期不再显式执行cast。
|
||||
if (OB_SUCC(ret)
|
||||
&& OB_LIKELY(!type.get_calc_meta().is_null())) {
|
||||
for (int i = 0; i < param_num; i++) {
|
||||
types[i].set_calc_meta(type.get_calc_meta());
|
||||
}
|
||||
@ -113,82 +196,213 @@ int ObExprBaseLeastGreatest::calc_result_typeN_oracle(
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObExprBaseLeastGreatest::calc_result_typeN_mysql(
|
||||
ObExprResType& type, ObExprResType* types, int64_t param_num, common::ObExprTypeCtx& type_ctx) const
|
||||
/* MySQL中greatest行为:
|
||||
* *. cached_field_type是用标准逻辑agg_field_type()推导, 作为结果列类型。
|
||||
* *. collation的计算过程: 如果参数中包含数值类型,则为binary,否则通过规则辗转计算
|
||||
* *. 计算过程却是根据get_cmp_type()来找到一个中间结果,然后所有数值转到中间结果上在作比较运算
|
||||
* 也就是说,比较过程与cached_field_type无关。get_calc_type()的逻辑是:只有参数都是STRING的情况下,
|
||||
* 返回类型才是STRING,否则返回数值类型。返回数值类型的时候,则所有参数都转成数值类型再做比较。
|
||||
*/
|
||||
int ObExprLeastGreatest::calc_result_typeN_mysql(ObExprResType &type,
|
||||
ObExprResType *types,
|
||||
int64_t param_num,
|
||||
common::ObExprTypeCtx &type_ctx) const
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObSQLSessionInfo* session = static_cast<const ObSQLSessionInfo*>(type_ctx.get_session());
|
||||
bool use_static_engine = session->use_static_typing_engine();
|
||||
if (use_static_engine && param_num % 3 != 0) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid argument count", K(ret), K(param_num));
|
||||
} else if (!use_static_engine) {
|
||||
ObExprOperator::calc_result_flagN(type, types, param_num);
|
||||
const ObLengthSemantics default_length_semantics =
|
||||
(OB_NOT_NULL(type_ctx.get_session()) ? type_ctx.get_session()->get_actual_nls_length_semantics() : LS_BYTE);
|
||||
if (OB_FAIL(calc_result_meta_for_comparison(
|
||||
type, types, param_num, type_ctx.get_coll_type(), default_length_semantics))) {
|
||||
LOG_WARN("calc result meta for comparison failed");
|
||||
} else {
|
||||
for (int64_t i = 0; i < param_num; i++) {
|
||||
types[i].set_calc_meta(type.get_calc_meta());
|
||||
}
|
||||
}
|
||||
if (OB_UNLIKELY(param_num <= 1)) {
|
||||
ret = OB_ERR_PARAM_SIZE;
|
||||
LOG_WARN("not enough param", K(ret));
|
||||
ObString func_name(get_name());
|
||||
LOG_USER_ERROR(OB_ERR_PARAM_SIZE, func_name.length(), func_name.ptr());
|
||||
} else {
|
||||
int64_t real_param_num = param_num / 3;
|
||||
ObExprOperator::calc_result_flagN(type, types, real_param_num);
|
||||
// don't cast parameter is all parameters are IntTC or UIntTC.
|
||||
const ObSQLSessionInfo *session = static_cast<const ObSQLSessionInfo*>(type_ctx.get_session());
|
||||
ObExprOperator::calc_result_flagN(type, types, param_num);
|
||||
// 如果所有参数都是IntTC或UIntTC, 那么不对参数做cast,结果类型根据参数的长度做类型提升。
|
||||
// 否则将所有参数都cast到推导出都calc_type
|
||||
bool all_integer = true;
|
||||
for (int i = 0; i < real_param_num && all_integer; ++i) {
|
||||
ObObjType type = types[i].get_type();
|
||||
if (!ob_is_integer_type(type) && ObNullType != type) {
|
||||
for (int i = 0; i < param_num && all_integer; ++i) {
|
||||
ObObjType obj_type = types[i].get_type();
|
||||
if (!ob_is_integer_type(obj_type) && ObNullType != obj_type) {
|
||||
all_integer = false;
|
||||
}
|
||||
}
|
||||
const ObLengthSemantics default_length_semantics =
|
||||
(OB_NOT_NULL(type_ctx.get_session()) ? type_ctx.get_session()->get_actual_nls_length_semantics() : LS_BYTE);
|
||||
if (OB_FAIL(calc_result_meta_for_comparison(
|
||||
type, types, real_param_num, type_ctx.get_coll_type(), default_length_semantics))) {
|
||||
const ObLengthSemantics default_length_semantics = (OB_NOT_NULL(type_ctx.get_session())
|
||||
? type_ctx.get_session()->get_actual_nls_length_semantics() : LS_BYTE);
|
||||
if (OB_FAIL(calc_result_meta_for_comparison(type, types, param_num, type_ctx.get_coll_type(),
|
||||
default_length_semantics))) {
|
||||
LOG_WARN("calc result meta for comparison failed");
|
||||
}
|
||||
// can't cast origin parameters.
|
||||
for (int64_t i = 0; i < real_param_num; i++) {
|
||||
// can't cast origin parameters.
|
||||
for (int64_t i = 0; i < param_num; i++) {
|
||||
types[i].set_calc_meta(types[i].get_obj_meta());
|
||||
}
|
||||
if (!all_integer || !type.is_integer_type()) {
|
||||
// compatible with MySQL. compare type and result type may be different.
|
||||
// resolver makes two copies of parameters. First for comparison and second for output result.
|
||||
for (int64_t i = 0; i < real_param_num; i++) {
|
||||
types[i + real_param_num].set_calc_meta(type.get_calc_meta());
|
||||
}
|
||||
for (int64_t i = 0; i < real_param_num; i++) {
|
||||
types[i + real_param_num * 2].set_calc_meta(type.get_obj_meta());
|
||||
if (all_integer && type.is_integer_type()) {
|
||||
type.set_calc_type(ObNullType);
|
||||
} else {
|
||||
for (int64_t i = 0; i < param_num; i++) {
|
||||
if (ob_is_enum_or_set_type(types[i].get_type())) {
|
||||
types[i].set_calc_type(type.get_calc_type());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObExprBaseLeastGreatest::calc(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum, bool least)
|
||||
int ObExprLeastGreatest::cg_expr(ObExprCGCtx &op_cg_ctx,
|
||||
const ObRawExpr &raw_expr,
|
||||
ObExpr &rt_expr) const
|
||||
{
|
||||
UNUSED(raw_expr);
|
||||
int ret = OB_SUCCESS;
|
||||
const uint32_t param_num = rt_expr.arg_cnt_;
|
||||
bool is_oracle_mode = lib::is_oracle_mode();
|
||||
if (OB_UNLIKELY(is_oracle_mode && param_num < 1)
|
||||
|| OB_UNLIKELY(!is_oracle_mode && param_num < 2)
|
||||
|| OB_ISNULL(rt_expr.args_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("args_ is null or too few arguments", K(ret), K(rt_expr.args_), K(param_num));
|
||||
} else if (OB_ISNULL(op_cg_ctx.session_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("session is null", K(ret));
|
||||
} else {
|
||||
const bool string_result = ob_is_string_or_lob_type(rt_expr.datum_meta_.type_);
|
||||
for (int i = 0; OB_SUCC(ret) && i < param_num; ++i) {
|
||||
if (OB_ISNULL(rt_expr.args_[i])) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("child of expr is null", K(ret), K(i));
|
||||
} else if (OB_ISNULL(rt_expr.args_[i]->basic_funcs_)
|
||||
|| OB_ISNULL(rt_expr.args_[i]->basic_funcs_->null_first_cmp_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("basic func of or cmp func is null", K(ret), K(rt_expr.args_[i]->basic_funcs_));
|
||||
} else if (is_oracle_mode
|
||||
&& rt_expr.args_[i]->datum_meta_.type_ != ObNullType
|
||||
&& rt_expr.datum_meta_.type_ != ObNullType
|
||||
&& (rt_expr.args_[i]->datum_meta_.type_ != rt_expr.datum_meta_.type_
|
||||
|| (string_result && rt_expr.args_[i]->datum_meta_.cs_type_ != rt_expr.datum_meta_.cs_type_))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("all param meta should be same", K(ret), K(i), K(rt_expr.args_[i]->datum_meta_),
|
||||
K(rt_expr.datum_meta_));
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
if (T_FUN_SYS_GREATEST == type_) {
|
||||
rt_expr.eval_func_ = ObExprGreatest::calc_greatest;
|
||||
} else {
|
||||
rt_expr.eval_func_ = ObExprLeast::calc_least;
|
||||
}
|
||||
const ObObjMeta &cmp_meta = result_type_.get_calc_meta();
|
||||
const bool is_explicit_cast = false;
|
||||
const int32_t result_flag = 0;
|
||||
ObCastMode cm = CM_NONE;
|
||||
if (!is_oracle_mode && !cmp_meta.is_null()) {
|
||||
DatumCastExtraInfo *info = OB_NEWx(DatumCastExtraInfo, op_cg_ctx.allocator_, *(op_cg_ctx.allocator_), type_);
|
||||
if (OB_ISNULL(info)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("alloc memory failed", K(ret));
|
||||
} else if (OB_FAIL(ObSQLUtils::get_default_cast_mode(is_explicit_cast, result_flag,
|
||||
op_cg_ctx.session_, cm))) {
|
||||
LOG_WARN("get default cast mode failed", K(ret));
|
||||
} else if (CS_TYPE_INVALID == cmp_meta.get_collation_type()) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("compare cs type is invalid", K(ret), K(cmp_meta));
|
||||
} else {
|
||||
info->cmp_meta_.type_ = cmp_meta.get_type();
|
||||
info->cmp_meta_.cs_type_ = cmp_meta.get_collation_type();
|
||||
info->cmp_meta_.scale_ = cmp_meta.get_scale();
|
||||
info->cm_ = cm;
|
||||
rt_expr.extra_info_ = info;
|
||||
ObDatumCmpFuncType cmp_func = ObDatumFuncs::get_nullsafe_cmp_func(cmp_meta.get_type(),
|
||||
cmp_meta.get_type(),
|
||||
NULL_LAST,
|
||||
cmp_meta.get_collation_type(),
|
||||
lib::is_oracle_mode());
|
||||
if (OB_ISNULL(cmp_func)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("invalid cmp type of params", K(ret), K(cmp_meta));
|
||||
} else if (OB_ISNULL(rt_expr.inner_functions_ =
|
||||
reinterpret_cast<void**>(op_cg_ctx.allocator_->alloc(sizeof(void*))))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("alloc memory failed", K(ret));
|
||||
} else {
|
||||
rt_expr.inner_func_cnt_ = 1;
|
||||
rt_expr.inner_functions_[0] = reinterpret_cast<void*>(cmp_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("least cg", K(result_type_));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObExprLeastGreatest::cast_param(const ObExpr &src_expr, ObEvalCtx &ctx,
|
||||
const ObDatumMeta &dst_meta,
|
||||
const ObCastMode &cm, ObIAllocator &allocator,
|
||||
ObDatum &res_datum)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const bool string_type = ob_is_string_type(dst_meta.type_);
|
||||
if (src_expr.datum_meta_.type_ == dst_meta.type_
|
||||
&& (!string_type || src_expr.datum_meta_.cs_type_ == dst_meta.cs_type_)) {
|
||||
res_datum = src_expr.locate_expr_datum(ctx);
|
||||
} else if (OB_ISNULL(ctx.datum_caster_) && OB_FAIL(ctx.init_datum_caster())) {
|
||||
LOG_WARN("init datum caster failed", K(ret));
|
||||
} else {
|
||||
ObDatum *cast_datum = NULL;
|
||||
if (OB_FAIL(ctx.datum_caster_->to_type(dst_meta, src_expr, cm, cast_datum, ctx.get_batch_idx()))) {
|
||||
LOG_WARN("fail to dynamic cast", K(ret), K(cm));
|
||||
} else if (OB_FAIL(res_datum.deep_copy(*cast_datum, allocator))) {
|
||||
LOG_WARN("deep copy datum failed", K(ret));
|
||||
} else {
|
||||
LOG_DEBUG("cast_param", K(src_expr), KP(ctx.frames_[src_expr.frame_idx_]),
|
||||
K(&(src_expr.locate_expr_datum(ctx))),
|
||||
K(ObToStringExpr(ctx, src_expr)), K(dst_meta), K(res_datum));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObExprLeastGreatest::cast_result(const ObExpr &src_expr, const ObExpr &dst_expr, ObEvalCtx &ctx,
|
||||
const ObCastMode &cm, ObDatum &expr_datum)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const bool string_type = ob_is_string_type(src_expr.datum_meta_.type_);
|
||||
if (src_expr.datum_meta_.type_ == dst_expr.datum_meta_.type_
|
||||
&& (!string_type || src_expr.datum_meta_.cs_type_ == dst_expr.datum_meta_.cs_type_)) {
|
||||
ObDatum *res_datum = nullptr;
|
||||
if (OB_FAIL(src_expr.eval(ctx, res_datum))) {
|
||||
LOG_WARN("eval param value failed", K(ret));
|
||||
} else {
|
||||
expr_datum = *res_datum;
|
||||
}
|
||||
} else if (OB_ISNULL(ctx.datum_caster_) && OB_FAIL(ctx.init_datum_caster())) {
|
||||
LOG_WARN("init datum caster failed", K(ret));
|
||||
} else {
|
||||
ObDatum *cast_datum = NULL;
|
||||
if (OB_FAIL(ctx.datum_caster_->to_type(dst_expr.datum_meta_, src_expr, cm, cast_datum, ctx.get_batch_idx()))) {
|
||||
LOG_WARN("fail to dynamic cast", K(ret));
|
||||
} else if (OB_FAIL(dst_expr.deep_copy_datum(ctx, *cast_datum))) {
|
||||
LOG_WARN("deep copy datum failed", K(ret));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObExprLeastGreatest::calc_mysql(const ObExpr &expr, ObEvalCtx &ctx,
|
||||
ObDatum &expr_datum, bool least)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
uint32_t param_num = expr.arg_cnt_;
|
||||
bool has_null = false;
|
||||
int64_t cmp_param_start = 0;
|
||||
int64_t cmp_param_end = param_num - 1;
|
||||
int64_t cmp_res_offset = 0;
|
||||
if (!lib::is_oracle_mode()) {
|
||||
cmp_param_start = param_num / 3;
|
||||
cmp_param_end = cmp_param_start * 2 - 1;
|
||||
cmp_res_offset = cmp_param_start;
|
||||
}
|
||||
// evaluate parameters if need. no need to continue to evaluate if null value found.
|
||||
// create table t(c1 int, c2 varchar(10));
|
||||
// insert into t values(null, 'a');
|
||||
// select least(c2, c1) from t; mysql reports warning, oracle reports an error
|
||||
// select least(c1, c2) from t; mysql reports no warning, oracle output null.
|
||||
for (int i = cmp_param_start; OB_SUCC(ret) && !has_null && i <= cmp_param_end; ++i) {
|
||||
ObDatum* tmp_datum = NULL;
|
||||
//这里要对参数进行按需求值,发现有参数值为null的话不再计算后面的参数的值
|
||||
//create table t(c1 int, c2 varchar(10));
|
||||
//insert into t values(null, 'a');
|
||||
//select least(c2, c1) from t; mysql会报warning, oracle会报错
|
||||
//select least(c1, c2) from t; mysql不会报warning, oracle正常输出null
|
||||
for (int i = 0; OB_SUCC(ret) && !has_null && i < param_num; ++i) {
|
||||
ObDatum *tmp_datum = NULL;
|
||||
if (OB_FAIL(expr.args_[i]->eval(ctx, tmp_datum))) {
|
||||
LOG_WARN("eval param value failed", K(ret), K(i));
|
||||
} else {
|
||||
@ -198,19 +412,15 @@ int ObExprBaseLeastGreatest::calc(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if all params and integer and result type is also integer, there is no inner_function of least expr.
|
||||
// otherwise, inner_func_cnt_ will be one. It stores the cmp function for parameters.
|
||||
if (!has_null && OB_SUCC(ret)) {
|
||||
bool all_integer = !lib::is_oracle_mode();
|
||||
for (int i = cmp_param_start; all_integer && i <= cmp_param_end; i++) {
|
||||
if (!ob_is_integer_type(expr.args_[i]->datum_meta_.type_)) {
|
||||
all_integer = false;
|
||||
}
|
||||
}
|
||||
const bool all_integer = 0 == expr.inner_func_cnt_;
|
||||
// compare all params.
|
||||
if (all_integer) {
|
||||
if (ob_is_int_tc(expr.datum_meta_.type_)) {
|
||||
int64_t minmax_value = expr.locate_param_datum(ctx, cmp_param_start).get_int();
|
||||
for (int i = cmp_param_start + 1; i <= cmp_param_end; ++i) {
|
||||
int64_t minmax_value = expr.locate_param_datum(ctx, 0).get_int();
|
||||
for (int i = 1; i < param_num; ++i) {
|
||||
int64_t new_value = expr.locate_param_datum(ctx, i).get_int();
|
||||
if (least != (minmax_value < new_value)) {
|
||||
minmax_value = new_value;
|
||||
@ -218,8 +428,8 @@ int ObExprBaseLeastGreatest::calc(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& e
|
||||
}
|
||||
expr_datum.set_int(minmax_value);
|
||||
} else {
|
||||
uint64_t minmax_value = expr.locate_param_datum(ctx, cmp_param_start).get_uint();
|
||||
for (int i = cmp_param_start + 1; i <= cmp_param_end; ++i) {
|
||||
uint64_t minmax_value = expr.locate_param_datum(ctx, 0).get_uint();
|
||||
for (int i = 1; i < param_num; ++i) {
|
||||
uint64_t new_value = expr.locate_param_datum(ctx, i).get_uint();
|
||||
if (least != (minmax_value < new_value)) {
|
||||
minmax_value = new_value;
|
||||
@ -227,39 +437,37 @@ int ObExprBaseLeastGreatest::calc(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& e
|
||||
}
|
||||
expr_datum.set_uint(minmax_value);
|
||||
}
|
||||
} else if (OB_ISNULL(expr.extra_info_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("extra info is null", K(ret));
|
||||
} else {
|
||||
int res_idx = cmp_param_start;
|
||||
ObDatum* minmax_param = static_cast<ObDatum*>(&expr.locate_param_datum(ctx, res_idx));
|
||||
for (int i = cmp_param_start + 1; OB_SUCC(ret) && i <= cmp_param_end; ++i) {
|
||||
CK(expr.args_[res_idx]->datum_meta_.type_ == expr.args_[i]->datum_meta_.type_);
|
||||
ObDatumCmpFuncType cmp_func = expr.args_[res_idx]->basic_funcs_->null_first_cmp_;
|
||||
ObDatum* cur_param = static_cast<ObDatum*>(&expr.locate_param_datum(ctx, i));
|
||||
int cmp_res = cmp_func(*minmax_param, *cur_param);
|
||||
if ((!least && cmp_res < 0) || (least && cmp_res > 0)) {
|
||||
res_idx = i;
|
||||
minmax_param = static_cast<ObDatum*>(&expr.locate_param_datum(ctx, res_idx));
|
||||
DatumCastExtraInfo *cast_info = static_cast<DatumCastExtraInfo *>(expr.extra_info_);
|
||||
int res_idx = 0;
|
||||
ObDatum minmax_datum;
|
||||
ObTempExprCtx::TempAllocGuard tmp_alloc_guard(ctx);
|
||||
ObDatumCmpFuncType cmp_func = reinterpret_cast<ObDatumCmpFuncType>(expr.inner_functions_[0]);
|
||||
if (OB_SUCC(ret) &&
|
||||
OB_FAIL(cast_param(*expr.args_[0], ctx, cast_info->cmp_meta_, cast_info->cm_,
|
||||
tmp_alloc_guard.get_allocator(), minmax_datum))) {
|
||||
LOG_WARN("cast param failed", K(ret));
|
||||
}
|
||||
for (int i = 1; OB_SUCC(ret) && i < param_num; ++i) {
|
||||
ObDatum cur_datum;
|
||||
if (OB_FAIL(cast_param(*expr.args_[i], ctx, cast_info->cmp_meta_, cast_info->cm_,
|
||||
tmp_alloc_guard.get_allocator(), cur_datum))) {
|
||||
LOG_WARN("cast param failed", K(ret));
|
||||
} else {
|
||||
int cmp_res = cmp_func(minmax_datum, cur_datum);
|
||||
if((!least && cmp_res < 0) || (least && cmp_res > 0)) {
|
||||
res_idx = i;
|
||||
minmax_datum = cur_datum;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ok, we got the least / greatest param.
|
||||
if (OB_SUCC(ret)) {
|
||||
res_idx += cmp_res_offset;
|
||||
const ObObjType result_type = expr.datum_meta_.type_;
|
||||
const ObCollationType result_cs_type = expr.datum_meta_.cs_type_;
|
||||
const ObObjType param_type = expr.args_[res_idx]->datum_meta_.type_;
|
||||
const ObCollationType param_cs_type = expr.args_[res_idx]->datum_meta_.cs_type_;
|
||||
ObDatum* res_datum = nullptr;
|
||||
bool result_string_type = ob_is_string_or_enumset_type(result_type) || ob_is_text_tc(result_type);
|
||||
if (OB_LIKELY(result_type == param_type && (!result_string_type || result_cs_type == param_cs_type))) {
|
||||
// collation type is compared in string comparision
|
||||
if (OB_FAIL(expr.args_[res_idx]->eval(ctx, res_datum))) {
|
||||
LOG_WARN("eval param value failed", K(ret), K(res_idx));
|
||||
} else {
|
||||
ObDatum& dst_datum = static_cast<ObDatum&>(expr_datum);
|
||||
dst_datum = *res_datum;
|
||||
}
|
||||
} else {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected result type", K(result_type), K(param_type), K(result_cs_type), K(param_cs_type));
|
||||
if (OB_FAIL(cast_result(*expr.args_[res_idx], expr, ctx, cast_info->cm_, expr_datum))) {
|
||||
LOG_WARN("cast result failed", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -267,117 +475,69 @@ int ObExprBaseLeastGreatest::calc(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& e
|
||||
return ret;
|
||||
}
|
||||
|
||||
ObExprBaseLeast::ObExprBaseLeast(ObIAllocator& alloc, int32_t param_num, ObExprOperatorType type /* T_FUN_SYS_LEAST */,
|
||||
const char* name /* N_LEAST*/)
|
||||
: ObExprBaseLeastGreatest(alloc, type, name, param_num)
|
||||
{}
|
||||
|
||||
ObExprBaseLeast::~ObExprBaseLeast()
|
||||
{}
|
||||
|
||||
int ObExprBaseLeast::calc_result_typeN(
|
||||
ObExprResType& type, ObExprResType* types_stack, int64_t param_num, common::ObExprTypeCtx& type_ctx) const
|
||||
int ObExprLeastGreatest::calc_oracle(const ObExpr &expr, ObEvalCtx &ctx,
|
||||
ObDatum &expr_datum, bool least)
|
||||
{
|
||||
UNUSED(type);
|
||||
UNUSED(types_stack);
|
||||
UNUSED(param_num);
|
||||
UNUSED(type_ctx);
|
||||
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
|
||||
int ObExprBaseLeast::calc_resultN(ObObj& result, const ObObj* objs_stack, int64_t param_num, ObExprCtx& expr_ctx) const
|
||||
{
|
||||
return ObMinMaxExprOperator::calc_(result, objs_stack, param_num, result_type_, expr_ctx, CO_LT, need_cast_, get_type());
|
||||
}
|
||||
|
||||
ObExprLeastMySQL::ObExprLeastMySQL(ObIAllocator& alloc) : ObExprBaseLeast(alloc, MORE_THAN_ONE)
|
||||
{}
|
||||
|
||||
ObExprLeastMySQL::~ObExprLeastMySQL()
|
||||
{}
|
||||
|
||||
int ObExprLeastMySQL::calc_result_typeN(
|
||||
ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const
|
||||
{
|
||||
return calc_result_typeN_mysql(type, types, param_num, type_ctx);
|
||||
}
|
||||
|
||||
ObExprLeastMySQLInner::ObExprLeastMySQLInner(ObIAllocator& alloc)
|
||||
: ObExprBaseLeast(alloc, MORE_THAN_ONE, T_FUN_SYS_LEAST_INNER, "")
|
||||
{}
|
||||
|
||||
ObExprLeastMySQLInner::~ObExprLeastMySQLInner()
|
||||
{}
|
||||
|
||||
int ObExprLeastMySQLInner::calc_result_typeN(
|
||||
ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const
|
||||
{
|
||||
return calc_result_typeN_mysql(type, types, param_num, type_ctx);
|
||||
}
|
||||
|
||||
ObExprOracleLeast::ObExprOracleLeast(ObIAllocator& alloc) : ObExprBaseLeast(alloc, MORE_THAN_ZERO)
|
||||
{}
|
||||
|
||||
ObExprOracleLeast::~ObExprOracleLeast()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Oracle, result type of greatest and least is same as first parameter.
|
||||
*/
|
||||
int ObExprOracleLeast::calc_result_typeN(
|
||||
ObExprResType& type, ObExprResType* types, int64_t param_num, ObExprTypeCtx& type_ctx) const
|
||||
{
|
||||
return calc_result_typeN_oracle(type, types, param_num, type_ctx);
|
||||
}
|
||||
|
||||
int ObExprBaseLeast::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const
|
||||
{
|
||||
UNUSED(op_cg_ctx);
|
||||
UNUSED(raw_expr);
|
||||
int ret = OB_SUCCESS;
|
||||
bool all_same_type = true;
|
||||
const uint32_t param_num = rt_expr.arg_cnt_;
|
||||
bool is_oracle_mode = lib::is_oracle_mode();
|
||||
if (OB_UNLIKELY(is_oracle_mode && param_num < 1) ||
|
||||
OB_UNLIKELY(!is_oracle_mode && (param_num < 2 || param_num % 3 != 0)) || OB_ISNULL(rt_expr.args_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("args_ is null or too few arguments", K(ret), K(rt_expr.args_), K(param_num));
|
||||
} else {
|
||||
if (!is_oracle_mode) {
|
||||
const uint32_t real_param_num = param_num / 3;
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < real_param_num; i++) {
|
||||
if (OB_FAIL(ObStaticEngineExprCG::replace_var_rt_expr(
|
||||
rt_expr.args_[i], rt_expr.args_[i + real_param_num], &rt_expr, i + real_param_num))) {
|
||||
LOG_WARN("replace var rt expr failed", K(ret));
|
||||
} else if (OB_FAIL(ObStaticEngineExprCG::replace_var_rt_expr(
|
||||
rt_expr.args_[i], rt_expr.args_[i + 2 * real_param_num], &rt_expr, i + 2 * real_param_num))) {
|
||||
LOG_WARN("replace var rt expr failed", K(ret));
|
||||
}
|
||||
uint32_t param_num = expr.arg_cnt_;
|
||||
bool has_null = false;
|
||||
int64_t cmp_res_offset = 0;
|
||||
for (int i = 0; OB_SUCC(ret) && !has_null && i < param_num; ++i) {
|
||||
ObDatum *tmp_datum = NULL;
|
||||
if (OB_FAIL(expr.args_[i]->eval(ctx, tmp_datum))) {
|
||||
LOG_WARN("eval param value failed", K(ret), K(i));
|
||||
} else {
|
||||
if (tmp_datum->is_null()) {
|
||||
has_null = true;
|
||||
expr_datum.set_null();
|
||||
}
|
||||
}
|
||||
for (int i = 0; OB_SUCC(ret) && i < param_num; ++i) {
|
||||
if (OB_ISNULL(rt_expr.args_[i])) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("child of expr is null", K(ret), K(i));
|
||||
} else if (OB_ISNULL(rt_expr.args_[i]->basic_funcs_) ||
|
||||
OB_ISNULL(rt_expr.args_[i]->basic_funcs_->null_first_cmp_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("basic func of or cmp func is null", K(ret), K(rt_expr.args_[i]->basic_funcs_));
|
||||
}
|
||||
if (!has_null && OB_SUCC(ret)) {
|
||||
// compare all params.
|
||||
int res_idx = 0;
|
||||
ObDatum *minmax_param = &expr.locate_param_datum(ctx, res_idx);
|
||||
for (int i = 1; OB_SUCC(ret) && i < param_num; ++i) {
|
||||
ObDatumCmpFuncType cmp_func = expr.args_[res_idx]->basic_funcs_->null_first_cmp_;
|
||||
ObDatum *cur_param = &expr.locate_param_datum(ctx, i);
|
||||
int cmp_res = cmp_func(*minmax_param, *cur_param);
|
||||
if((!least && cmp_res < 0) || (least && cmp_res > 0)) {
|
||||
res_idx = i;
|
||||
minmax_param = static_cast<ObDatum *>(&expr.locate_param_datum(ctx, res_idx));
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
rt_expr.eval_func_ = ObExprBaseLeast::calc_least;
|
||||
ObDatum *res_datum = nullptr;
|
||||
if (OB_FAIL(expr.args_[res_idx]->eval(ctx, res_datum))) {
|
||||
LOG_WARN("eval param value failed", K(ret), K(res_idx));
|
||||
} else {
|
||||
ObDatum &dst_datum = static_cast<ObDatum &>(expr_datum);
|
||||
dst_datum = *res_datum;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// same type params
|
||||
int ObExprBaseLeast::calc_least(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum)
|
||||
ObExprLeast::ObExprLeast(common::ObIAllocator &alloc)
|
||||
: ObExprLeastGreatest(alloc,
|
||||
T_FUN_SYS_LEAST,
|
||||
N_LEAST,
|
||||
MORE_THAN_ZERO)
|
||||
{
|
||||
return ObExprBaseLeastGreatest::calc(expr, ctx, expr_datum, true);
|
||||
}
|
||||
|
||||
} // namespace sql
|
||||
} // namespace oceanbase
|
||||
//same type params
|
||||
int ObExprLeast::calc_least(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (is_oracle_mode()) {
|
||||
ret = ObExprLeastGreatest::calc_oracle(expr, ctx, expr_datum, true);
|
||||
} else {
|
||||
ret = ObExprLeastGreatest::calc_mysql(expr, ctx, expr_datum, true);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user