Files
oceanbase/src/sql/engine/expr/ob_expr_width_bucket.cpp
2023-04-27 11:11:24 +00:00

248 lines
11 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/ob_sql_utils.h"
#include "lib/utility/utility.h"
#include "sql/engine/expr/ob_expr_width_bucket.h"
#include "sql/engine/expr/ob_expr_util.h"
#include "sql/engine/expr/ob_expr_result_type_util.h"
#include "sql/session/ob_sql_session_info.h"
#include "lib/charset/ob_dtoa.h"
using namespace oceanbase::common;
namespace oceanbase
{
namespace sql
{
ObExprWidthBucket::ObExprWidthBucket(common::ObIAllocator &alloc) :
ObFuncExprOperator(alloc, T_FUN_SYS_WIDTH_BUCKET, N_WIDTH_BUCKET, 4, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION)
{
}
int ObExprWidthBucket::calc_result_typeN(ObExprResType &type,
ObExprResType *types,
int64_t param_num,
ObExprTypeCtx &type_ctx) const
{
UNUSED(type_ctx);
int ret = OB_SUCCESS;
if (OB_UNLIKELY(OB_ISNULL(types) || 4 != param_num)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(types), K(param_num), K(ret));
} else if (OB_UNLIKELY(ObNullType == types[0].get_type())) {
ret = OB_ERR_ARGUMENT_SHOULD_NUMERIC_DATE_DATETIME_TYPE;
LOG_WARN("first argument should be of numeric or date/datetime type",K(ret));
} else if (OB_LIKELY(NOT_ROW_DIMENSION == row_dimension_)) {
type.set_type(ObNumberType);
const ObAccuracy &acc =
ObAccuracy::DDL_DEFAULT_ACCURACY2[common::ORACLE_MODE][common::ObNumberType];
common::ObObjType calc_type = types[0].get_type();
type.set_scale(acc.get_scale());
type.set_precision(acc.get_precision());
if (ob_is_numeric_type(calc_type)) {
calc_type = ObNumberType;
} else {
switch (calc_type) {
case ObDateTimeType: break;
case ObTimestampNanoType: break;
case ObIntervalYMType: break;
case ObIntervalDSType: break;
case ObTimestampTZType:
case ObTimestampLTZType:
calc_type = ObTimestampLTZType;
break;
default:
ret = OB_ERR_ARGUMENT_SHOULD_NUMERIC_DATE_DATETIME_TYPE;
LOG_WARN("first parameter must be number, date or timestamp type", K(ret), K(calc_type));
break;
}
}
if (OB_SUCC(ret)) {
types[0].set_calc_type(calc_type);
types[1].set_calc_type(calc_type);
types[2].set_calc_type(calc_type);
types[3].set_calc_type(ObNumberType);
types[3].set_scale(0);
}
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
return ret;
}
int ObExprWidthBucket::construct_param_nmb(const int64_t expr_value,
const int64_t start_value,
const int64_t end_value,
common::ObIAllocator &alloc,
common::number::ObNumber &expr_nmb,
common::number::ObNumber &start_nmb,
common::number::ObNumber &end_nmb)
{
int ret = OB_SUCCESS;
if (OB_FAIL(expr_nmb.from(expr_value, alloc))) {
LOG_WARN("expr number from int64 failed", K(expr_value), K(ret));
} else if (OB_FAIL(start_nmb.from(start_value, alloc))) {
LOG_WARN("start number from int64 failed", K(start_value), K(ret));
} else if (OB_FAIL(end_nmb.from(end_value, alloc))) {
LOG_WARN("end number from int64 failed", K(end_value), K(ret));
}
return ret;
}
int ObExprWidthBucket::calc_time_type(const int64_t time_sec1, const int64_t time_frac_sec1,
const int64_t time_sec2, const int64_t time_frac_sec2,
const int64_t time_sec3, const int64_t time_frac_sec3,
const int64_t multiple,
ObIAllocator &alloc,
number::ObNumber &e_nmb, number::ObNumber &start_nmb,
number::ObNumber &end_nmb)
{
int ret = OB_SUCCESS;
number::ObNumber time_sec1_nmb;
number::ObNumber time_frac_sec1_nmb;
number::ObNumber time_sec2_nmb;
number::ObNumber time_frac_sec2_nmb;
number::ObNumber time_sec3_nmb;
number::ObNumber time_frac_sec3_nmb;
number::ObNumber multiple_nmb;
if (OB_FAIL(construct_param_nmb(time_sec1, time_sec2, time_sec3,
alloc, time_sec1_nmb, time_sec2_nmb, time_sec3_nmb))) {
LOG_WARN("construct param nmb failed", K(ret));
} else if (OB_FAIL(construct_param_nmb(time_frac_sec1, time_frac_sec2, time_frac_sec3,
alloc, time_frac_sec1_nmb, time_frac_sec2_nmb, time_frac_sec3_nmb))) {
LOG_WARN("construct param nmb failed", K(ret));
} else if (OB_FAIL(multiple_nmb.from(multiple, alloc))) {
LOG_WARN("create obnumber from const int64 failed", K(ret));
} else if (OB_FAIL(time_sec1_nmb.mul(multiple_nmb, time_sec1_nmb, alloc))) {
LOG_WARN("time_sec1_nmb mul 1000 failed", K(ret));
} else if (OB_FAIL(time_sec1_nmb.add(time_frac_sec1_nmb, e_nmb, alloc))) {
LOG_WARN("time_sec1_nmb add time_frac_sec1_nmb failed", K(ret));
} else if (OB_FAIL(time_sec2_nmb.mul(multiple_nmb, time_sec2_nmb, alloc))) {
LOG_WARN("time_sec2_nmb mul 1000 failed", K(ret));
} else if (OB_FAIL(time_sec2_nmb.add(time_frac_sec2_nmb, start_nmb, alloc))) {
LOG_WARN("time_sec2_nmb add time_frac_sec2_nmb failed", K(ret));
} else if (OB_FAIL(time_sec3_nmb.mul(multiple_nmb, time_sec3_nmb, alloc))) {
LOG_WARN("time_sec3_nmb mul 1000 failed", K(ret));
} else if (OB_FAIL(time_sec3_nmb.add(time_frac_sec3_nmb, end_nmb, alloc))) {
LOG_WARN("time_sec3_nmb add time_frac_sec3_nmb failed", K(ret));
}
return ret;
}
int ObExprWidthBucket::calc_width_bucket_expr(const ObExpr &expr, ObEvalCtx &ctx,
ObDatum &res)
{
int ret = OB_SUCCESS;
// width_bucket(e, start, end, bucket);
ObDatum *e = NULL;
ObDatum *start = NULL;
ObDatum *end = NULL;
ObDatum *bucket = NULL;
if (OB_UNLIKELY(4 != expr.arg_cnt_)) {
ret = OB_INVALID_ARGUMENT_NUM;
LOG_WARN("invalid arg cnt", K(ret), K(expr.arg_cnt_));
} else if (OB_FAIL(expr.eval_param_value(ctx, e, start, end, bucket))) {
LOG_WARN("eval param failed", K(ret));
} else if (e->is_null()) {
res.set_null();
} else if (OB_UNLIKELY(start->is_null())) {
ret = OB_ERR_INVALID_ARGUMENT_FOR_WIDTH_BUCKET;
LOG_USER_ERROR(OB_ERR_INVALID_ARGUMENT_FOR_WIDTH_BUCKET, "2");
} else if (OB_UNLIKELY(end->is_null())) {
ret = OB_ERR_INVALID_ARGUMENT_FOR_WIDTH_BUCKET;
LOG_USER_ERROR(OB_ERR_INVALID_ARGUMENT_FOR_WIDTH_BUCKET, "3");
} else if (OB_UNLIKELY(bucket->is_null())) {
ret = OB_ERR_INVALID_ARGUMENT_FOR_WIDTH_BUCKET;
LOG_USER_ERROR(OB_ERR_INVALID_ARGUMENT_FOR_WIDTH_BUCKET, "4");
} else {
number::ObNumber res_nmb;
number::ObNumber e_nmb;
number::ObNumber start_nmb;
number::ObNumber end_nmb;
number::ObNumber bucket_nmb(bucket->get_number());
const ObObjType target_type = expr.args_[0]->datum_meta_.type_;
ObEvalCtx::TempAllocGuard alloc_guard(ctx);
ObIAllocator &calc_alloc = alloc_guard.get_allocator();
if (ObNumberType == target_type) {
e_nmb = number::ObNumber(e->get_number());
start_nmb = number::ObNumber(start->get_number());
end_nmb = number::ObNumber(end->get_number());
} else if (ObDateTimeType == target_type) {
if (OB_FAIL(construct_param_nmb(e->get_datetime(),
start->get_datetime(),
end->get_datetime(),
calc_alloc, e_nmb, start_nmb, end_nmb))) {
LOG_WARN("construct param number failed", K(ret));
}
} else if (ObTimestampNanoType == target_type || ObTimestampLTZType == target_type) {
const int64_t time_usec1 = e->get_otimestamp_tiny().time_us_;
const int64_t time_usec2 = start->get_otimestamp_tiny().time_us_;
const int64_t time_usec3 = end->get_otimestamp_tiny().time_us_;
const int16_t time_nsec1 = e->get_otimestamp_tiny().time_ctx_.tail_nsec_;
const int16_t time_nsec2 = start->get_otimestamp_tiny().time_ctx_.tail_nsec_;
const int16_t time_nsec3 = end->get_otimestamp_tiny().time_ctx_.tail_nsec_;
if (OB_FAIL(calc_time_type(time_usec1, time_nsec1, time_usec2, time_nsec2,
time_usec3, time_nsec3, NSECS_PER_USEC, calc_alloc,
e_nmb, start_nmb, end_nmb))) {
LOG_WARN("calc_time_type faied", K(ret));
}
} else if (ObIntervalYMType == target_type) {
if (OB_FAIL(construct_param_nmb(e->get_interval_ym(),
start->get_interval_ym(),
end->get_interval_ym(),
calc_alloc, e_nmb, start_nmb, end_nmb))) {
LOG_WARN("construct param nmb failed", K(ret));
}
} else if (ObIntervalDSType == target_type) {
ObIntervalDSValue ds_value1 = e->get_interval_ds();
ObIntervalDSValue ds_value2 = start->get_interval_ds();
ObIntervalDSValue ds_value3 = end->get_interval_ds();
if (OB_FAIL(calc_time_type(ds_value1.nsecond_, ds_value1.fractional_second_,
ds_value2.nsecond_, ds_value2.fractional_second_,
ds_value3.nsecond_, ds_value3.fractional_second_,
NSECS_PER_SEC, calc_alloc,
e_nmb, start_nmb, end_nmb))) {
LOG_WARN("calc_time_type faied", K(ret));
}
} else {
}
if (OB_SUCC(ret)) {
number::ObNumber res_nmb;
ObNumStackOnceAlloc res_alloc;
if (OB_FAIL(e_nmb.width_bucket(start_nmb, end_nmb, bucket_nmb, res_nmb, res_alloc))) {
LOG_WARN("call width_bucket failed", K(ret));
} else {
res.set_number(res_nmb);
}
}
}
return ret;
}
int ObExprWidthBucket::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
int ret = OB_SUCCESS;
UNUSED(expr_cg_ctx);
UNUSED(raw_expr);
rt_expr.eval_func_ = calc_width_bucket_expr;
return ret;
}
} // namespace sql
} // namespace oceanbase