248 lines
11 KiB
C++
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
|