1918 lines
68 KiB
C++
1918 lines
68 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.
|
|
*/
|
|
|
|
// This file is for func json_value.
|
|
#define USING_LOG_PREFIX SQL_ENG
|
|
#include "ob_expr_json_value.h"
|
|
#include "sql/engine/expr/ob_expr_util.h"
|
|
#include "share/object/ob_obj_cast.h"
|
|
#include "sql/session/ob_sql_session_info.h"
|
|
#include "share/object/ob_obj_cast_util.h"
|
|
#include "share/object/ob_obj_cast.h"
|
|
#include "sql/engine/expr/ob_expr_cast.h"
|
|
#include "sql/engine/expr/ob_datum_cast.h"
|
|
#include "sql/resolver/expr/ob_raw_expr_util.h"
|
|
#include "lib/oblog/ob_log_module.h"
|
|
#include "ob_expr_json_func_helper.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
|
|
// from sql_parser_base.h
|
|
#define DEFAULT_STR_LENGTH -1
|
|
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase::sql;
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace sql
|
|
{
|
|
|
|
#define CAST_FAIL(stmt) \
|
|
(OB_UNLIKELY((OB_SUCCESS != (ret = get_cast_ret((stmt))))))
|
|
|
|
#define GET_SESSION() \
|
|
ObBasicSessionInfo *session = ctx.exec_ctx_.get_my_session(); \
|
|
if (OB_ISNULL(session)) { \
|
|
ret = OB_ERR_UNEXPECTED; \
|
|
LOG_WARN("session is NULL", K(ret)); \
|
|
} else
|
|
|
|
ObExprJsonValue::ObExprJsonValue(ObIAllocator &alloc)
|
|
: ObFuncExprOperator(alloc, T_FUN_SYS_JSON_VALUE, N_JSON_VALUE, MORE_THAN_TWO, NOT_ROW_DIMENSION)
|
|
{
|
|
}
|
|
|
|
ObExprJsonValue::~ObExprJsonValue()
|
|
{
|
|
}
|
|
|
|
int ObExprJsonValue::calc_result_typeN(ObExprResType& type,
|
|
ObExprResType* types_stack,
|
|
int64_t param_num,
|
|
ObExprTypeCtx& type_ctx) const
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_UNLIKELY(param_num != 7)) {
|
|
ret = OB_ERR_PARAM_SIZE;
|
|
LOG_WARN("invalid param number", K(ret), K(param_num));
|
|
} else {
|
|
//type.set_json();
|
|
// json doc : 0
|
|
ObObjType doc_type = types_stack[0].get_type();
|
|
if (types_stack[0].get_type() == ObNullType) {
|
|
} else if (!ObJsonExprHelper::is_convertible_to_json(doc_type)) {
|
|
ret = OB_ERR_INVALID_TYPE_FOR_JSON;
|
|
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_JSON, 1, "json_value");
|
|
LOG_WARN("Invalid type for json doc", K(doc_type));
|
|
} else if (ob_is_string_type(doc_type)) {
|
|
if (types_stack[0].get_collation_type() == CS_TYPE_BINARY) {
|
|
// unsuport string type with binary charset
|
|
ret = OB_ERR_INVALID_JSON_CHARSET;
|
|
LOG_WARN("Unsupport for string type with binary charset input.", K(ret), K(doc_type));
|
|
} else if (types_stack[0].get_charset_type() != CHARSET_UTF8MB4) {
|
|
types_stack[0].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
|
|
}
|
|
} else if (doc_type == ObJsonType) {
|
|
// do nothing
|
|
} else {
|
|
types_stack[0].set_calc_type(ObLongTextType);
|
|
types_stack[0].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
|
|
}
|
|
|
|
// json path : 1
|
|
if (OB_SUCC(ret)) {
|
|
if (types_stack[1].get_type() == ObNullType) {
|
|
// do nothing
|
|
} else if (ob_is_string_type(types_stack[1].get_type())) {
|
|
if (types_stack[1].get_charset_type() != CHARSET_UTF8MB4) {
|
|
types_stack[1].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
|
|
}
|
|
} else {
|
|
types_stack[1].set_calc_type(ObLongTextType);
|
|
types_stack[1].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
|
|
}
|
|
}
|
|
// returning type : 2
|
|
ObExprResType dst_type;
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(get_cast_type(types_stack[2], dst_type))) {
|
|
LOG_WARN("get cast dest type failed", K(ret));
|
|
} else if (OB_FAIL(set_dest_type(types_stack[0], type, dst_type, type_ctx))) {
|
|
LOG_WARN("set dest type failed", K(ret));
|
|
} else {
|
|
type.set_calc_collation_type(type.get_collation_type());
|
|
}
|
|
}
|
|
|
|
// empty : 3, 4
|
|
if (OB_SUCC(ret)) {
|
|
ObExprResType temp_type;
|
|
if (types_stack[3].get_type() == ObNullType) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("<empty type> param type is unexpected", K(types_stack[3].get_type()));
|
|
} else if (types_stack[3].get_type() != ObIntType) {
|
|
types_stack[3].set_calc_type(ObIntType);
|
|
} else if (types_stack[4].get_type() == ObNullType) {
|
|
// do nothing
|
|
} else if (OB_FAIL(set_dest_type(types_stack[4], temp_type, dst_type, type_ctx))) {
|
|
LOG_WARN("set dest type failed", K(ret));
|
|
} else {
|
|
types_stack[4].set_calc_type(temp_type.get_type());
|
|
types_stack[4].set_calc_collation_type(temp_type.get_collation_type());
|
|
types_stack[4].set_calc_collation_level(temp_type.get_collation_level());
|
|
types_stack[4].set_calc_accuracy(temp_type.get_accuracy());
|
|
}
|
|
}
|
|
|
|
// error : 5, 6
|
|
if (OB_SUCC(ret)) {
|
|
ObExprResType temp_type;
|
|
if (types_stack[5].get_type() == ObNullType) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("<error type> param type is unexpected", K(types_stack[5].get_type()));
|
|
} else if (types_stack[5].get_type() != ObIntType) {
|
|
types_stack[5].set_calc_type(ObIntType);
|
|
} else if (types_stack[6].get_type() == ObNullType) {
|
|
// do nothing
|
|
} else if (OB_FAIL(set_dest_type(types_stack[6], temp_type, dst_type, type_ctx))) {
|
|
LOG_WARN("set dest type failed", K(ret));
|
|
} else {
|
|
types_stack[6].set_calc_type(temp_type.get_type());
|
|
types_stack[6].set_calc_collation_type(temp_type.get_collation_type());
|
|
types_stack[6].set_calc_collation_level(temp_type.get_collation_level());
|
|
types_stack[6].set_calc_accuracy(temp_type.get_accuracy());
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::calc_resultN(ObObj& result,
|
|
const ObObj *params,
|
|
int64_t params_count,
|
|
ObExprCtx& expr_ctx) const
|
|
{
|
|
INIT_SUCC(ret);
|
|
ObIAllocator *allocator = expr_ctx.calc_buf_;
|
|
bool is_cover_by_error = true;
|
|
bool is_null_result = false;
|
|
ObIJsonBase *j_base = NULL;
|
|
|
|
if (OB_ISNULL(params) || OB_UNLIKELY(params_count != 7)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid arguments", K(ret), K(params), K(params_count));
|
|
} else if (OB_ISNULL(allocator)) { // check allocator
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("varchar buffer not init", K(ret));
|
|
} else if (OB_FAIL(param_eval(expr_ctx, params[0], 0))) {
|
|
LOG_WARN("failed: eval json doc", K(ret));
|
|
} else {
|
|
ObObjType type = params[0].get_type();
|
|
if (type == ObNullType || params[0].is_null()) {
|
|
is_null_result = true;
|
|
} else if (type != ObJsonType && !ob_is_string_type(type)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input type error", K(type));
|
|
} else {
|
|
ObString j_str = params[0].get_string();
|
|
ObJsonInType j_in_type = ObJsonExprHelper::get_json_internal_type(type);
|
|
if (j_str.length() == 0) { // maybe input json doc is null type
|
|
is_null_result = true;
|
|
} else if (OB_FAIL(ObJsonBaseFactory::get_json_base(allocator, j_str, j_in_type,
|
|
j_in_type, j_base))) {
|
|
LOG_WARN("fail to get json base.", K(ret), K(type), K(j_str), K(j_in_type));
|
|
if (ret == OB_ERR_JSON_OUT_OF_DEPTH) {
|
|
is_cover_by_error = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// parse return node acc
|
|
ObAccuracy accuracy;
|
|
ObObjType dst_type;
|
|
if (is_cover_by_error) { // adapt mysql, Parse return node even if parse json doc wrong.
|
|
int32_t temp_ret = param_eval(expr_ctx, params[2], 2);
|
|
if (temp_ret != OB_SUCCESS) {
|
|
ret = (ret == OB_SUCCESS) ? temp_ret : ret;
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval json arg failed", K(temp_ret));
|
|
} else {
|
|
temp_ret = get_accuracy_internal(accuracy, dst_type, params[2].get_int(),
|
|
result_type_.get_length_semantics());
|
|
if (temp_ret != OB_SUCCESS) {
|
|
ret = (ret == OB_SUCCESS) ? temp_ret : ret;
|
|
is_cover_by_error = false;
|
|
LOG_WARN("get accuracy failed", K(temp_ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
// parse empty option
|
|
ObObj empty_val;
|
|
uint8_t empty_type = OB_JSON_ON_RESPONSE_IMPLICIT;
|
|
if (OB_SUCC(ret) && !is_null_result) {
|
|
ret = get_on_empty_or_error_old(params, expr_ctx, dst_type, 3, is_cover_by_error,
|
|
accuracy, empty_type, &empty_val);
|
|
}
|
|
|
|
// parse error option
|
|
ObObj error_val;
|
|
uint8_t error_type = OB_JSON_ON_RESPONSE_IMPLICIT;
|
|
if (OB_SUCC(ret) && !is_null_result) {
|
|
ret = get_on_empty_or_error_old(params, expr_ctx, dst_type, 5, is_cover_by_error,
|
|
accuracy, error_type, &error_val);
|
|
} else if (is_cover_by_error) { // always get error option for return default value on error
|
|
int temp_ret = get_on_empty_or_error_old(params, expr_ctx, dst_type, 5, is_cover_by_error,
|
|
accuracy, error_type, &error_val);
|
|
if (temp_ret != OB_SUCCESS) {
|
|
LOG_WARN("failed to get on empty or error.", K(ret), K(dst_type));
|
|
}
|
|
}
|
|
|
|
// parse json path and do seek
|
|
ObObj *return_val = NULL;
|
|
ObJsonBaseVector hits;
|
|
if (OB_SUCC(ret) && !is_null_result) {
|
|
if (OB_FAIL(param_eval(expr_ctx, params[1], 1))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval json arg failed", K(ret));
|
|
} else {
|
|
ObObjType type = params[1].get_type();
|
|
if (type == ObNullType || params[1].is_null()) {
|
|
is_null_result = true;
|
|
} else if (!ob_is_string_type(type)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input type error", K(type));
|
|
} else {
|
|
// Old engine not support op_ctx. use local cache.
|
|
ObJsonPathCache ctx_cache(allocator);
|
|
ObJsonPathCache *path_cache = &ctx_cache;
|
|
ObString j_path_text = params[1].get_string();
|
|
ObJsonPath *j_path;
|
|
if (j_path_text.length() == 0) {
|
|
is_null_result = true;
|
|
} else if (OB_FAIL(ObJsonExprHelper::find_and_add_cache(path_cache, j_path,
|
|
j_path_text, 1, true))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("parse text to path failed", K(j_path_text), K(ret));
|
|
} else if (OB_FAIL(j_base->seek(*j_path, j_path->path_node_cnt(), true, false, hits))) {
|
|
LOG_WARN("json seek failed", K(j_path_text), K(ret));
|
|
} else if (hits.size() == 0) {
|
|
switch (empty_type) {
|
|
case OB_JSON_ON_RESPONSE_ERROR: {
|
|
is_cover_by_error = false;
|
|
ret = OB_ERR_MISSING_JSON_VALUE;
|
|
LOG_USER_ERROR(OB_ERR_MISSING_JSON_VALUE, "json_value");
|
|
LOG_WARN("json value seek result empty.", K(hits.size()));
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_DEFAULT: {
|
|
return_val = &empty_val;
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_NULL:
|
|
case OB_JSON_ON_RESPONSE_IMPLICIT: {
|
|
is_null_result = true;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
} else if (hits.size() > 1) {
|
|
// return val decide by error option
|
|
switch (error_type) {
|
|
case OB_JSON_ON_RESPONSE_ERROR: {
|
|
ret = OB_ERR_MULTIPLE_JSON_VALUES;
|
|
LOG_USER_ERROR(OB_ERR_MULTIPLE_JSON_VALUES, "json_value");
|
|
LOG_WARN("json value seek result more than one.", K(hits.size()));
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_DEFAULT: {
|
|
return_val = &error_val;
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_NULL:
|
|
case OB_JSON_ON_RESPONSE_IMPLICIT: {
|
|
is_null_result = true;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
} else if (hits[0]->json_type() == ObJsonNodeType::J_NULL) {
|
|
is_null_result = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// fill output
|
|
if (OB_UNLIKELY(OB_FAIL(ret))) {
|
|
if (is_cover_by_error) {
|
|
try_set_error_val<ObObj>(result, ret, error_type, &error_val);
|
|
}
|
|
LOG_WARN("json_values failed", K(ret));
|
|
} else if (is_null_result){
|
|
result.set_null();
|
|
} else {
|
|
if (return_val != NULL) {
|
|
set_val(result, return_val);
|
|
} else {
|
|
ObCollationType in_coll_type = params[0].get_collation_type();
|
|
ObCollationType dst_coll_type = result_type_.get_collation_type();
|
|
ObCollationLevel dst_coll_level = result_type_.get_collation_level();
|
|
ret = cast_to_res(allocator, expr_ctx, hits[0], error_type, &error_val,
|
|
accuracy, dst_type, in_coll_type, dst_coll_type, dst_coll_level, result);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::eval_json_value(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res)
|
|
{
|
|
INIT_SUCC(ret);
|
|
ObDatum *json_datum = NULL;
|
|
ObExpr *json_arg = expr.args_[0];
|
|
ObObjType type = json_arg->datum_meta_.type_;
|
|
bool is_cover_by_error = true;
|
|
bool is_null_result = false;
|
|
ObDatum *return_val = NULL;
|
|
common::ObArenaAllocator &temp_allocator = ctx.get_reset_tmp_alloc();
|
|
ObIJsonBase *j_base = NULL;
|
|
|
|
// parse json doc
|
|
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
|
|
LOG_WARN("eval json arg failed", K(ret));
|
|
is_cover_by_error = false;
|
|
} else if (type == ObNullType || json_datum->is_null()) {
|
|
is_null_result = true;
|
|
} else if (type != ObJsonType && !ob_is_string_type(type)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input type error", K(type));
|
|
} else {
|
|
ObString j_str = json_datum->get_string();
|
|
ObJsonInType j_in_type = ObJsonExprHelper::get_json_internal_type(type);
|
|
if (j_str.length() == 0) { // maybe input json doc is null type
|
|
is_null_result = true;
|
|
} else if (OB_FAIL(ObJsonBaseFactory::get_json_base(&temp_allocator, j_str, j_in_type,
|
|
j_in_type, j_base))) {
|
|
LOG_WARN("fail to get json base.", K(ret), K(type), K(j_str), K(j_in_type));
|
|
if (ret == OB_ERR_JSON_OUT_OF_DEPTH) {
|
|
is_cover_by_error = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// parse return node acc
|
|
ObAccuracy accuracy;
|
|
ObObjType dst_type;
|
|
if (OB_SUCC(ret) && !is_null_result) {
|
|
ret = get_accuracy(expr, ctx, accuracy, dst_type, is_cover_by_error);
|
|
} else if (is_cover_by_error) { // when need error option, should do get accuracy
|
|
get_accuracy(expr, ctx, accuracy, dst_type, is_cover_by_error);
|
|
}
|
|
|
|
// parse empty option
|
|
ObDatum *empty_datum = NULL;
|
|
uint8_t empty_type = OB_JSON_ON_RESPONSE_IMPLICIT;
|
|
if (OB_SUCC(ret) && !is_null_result) {
|
|
ret = get_on_empty_or_error(expr, ctx, 3, is_cover_by_error, accuracy, empty_type, &empty_datum);
|
|
}
|
|
|
|
// parse error option
|
|
ObDatum *error_val = NULL;
|
|
uint8_t error_type = OB_JSON_ON_RESPONSE_IMPLICIT;
|
|
if (OB_SUCC(ret) && !is_null_result) {
|
|
ret = get_on_empty_or_error(expr, ctx, 5, is_cover_by_error, accuracy, error_type, &error_val);
|
|
} else if (is_cover_by_error) { // always get error option for return default value on error
|
|
int temp_ret = get_on_empty_or_error(expr, ctx, 5, is_cover_by_error, accuracy,
|
|
error_type, &error_val);
|
|
if (temp_ret != OB_SUCCESS) {
|
|
LOG_WARN("failed to get error option.", K(temp_ret));
|
|
}
|
|
}
|
|
|
|
// parse json path and do seek
|
|
ObJsonBaseVector hits;
|
|
if (OB_SUCC(ret) && !is_null_result) {
|
|
json_arg = expr.args_[1];
|
|
type = json_arg->datum_meta_.type_;
|
|
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval json arg failed", K(ret));
|
|
} else if (type == ObNullType || json_datum->is_null()) {
|
|
is_null_result = true;
|
|
} else if (!ob_is_string_type(type)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input type error", K(type));
|
|
} else {
|
|
ObString j_path_text = json_datum->get_string();
|
|
ObJsonPath *j_path;
|
|
if (j_path_text.length() == 0) {
|
|
is_null_result = true;
|
|
}
|
|
|
|
ObJsonPathCache ctx_cache(&temp_allocator);
|
|
ObJsonPathCache* path_cache = ObJsonExprHelper::get_path_cache_ctx(expr.expr_ctx_id_, &ctx.exec_ctx_);
|
|
path_cache = ((path_cache != NULL) ? path_cache : &ctx_cache);
|
|
|
|
if (OB_FAIL(ObJsonExprHelper::find_and_add_cache(path_cache, j_path, j_path_text, 1, true))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("parse text to path failed", K(json_datum->get_string()), K(ret));
|
|
} else if (OB_FAIL(j_base->seek(*j_path, j_path->path_node_cnt(), true, false, hits))) {
|
|
LOG_WARN("json seek failed", K(json_datum->get_string()), K(ret));
|
|
} else if (hits.size() == 0) {
|
|
switch (empty_type) {
|
|
case OB_JSON_ON_RESPONSE_ERROR: {
|
|
is_cover_by_error = false;
|
|
ret = OB_ERR_MISSING_JSON_VALUE;
|
|
LOG_USER_ERROR(OB_ERR_MISSING_JSON_VALUE, "json_value");
|
|
LOG_WARN("json value seek result empty.", K(hits.size()));
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_DEFAULT: {
|
|
return_val = empty_datum;
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_NULL:
|
|
case OB_JSON_ON_RESPONSE_IMPLICIT: {
|
|
is_null_result = true;
|
|
break;
|
|
}
|
|
default: // empty_type from get_on_empty_or_error has done range check, do nothing for default
|
|
break;
|
|
}
|
|
} else if (hits.size() > 1) {
|
|
// return val decide by error option
|
|
switch (error_type) {
|
|
case OB_JSON_ON_RESPONSE_ERROR: {
|
|
ret = OB_ERR_MULTIPLE_JSON_VALUES;
|
|
LOG_USER_ERROR(OB_ERR_MULTIPLE_JSON_VALUES, "json_value");
|
|
LOG_WARN("json value seek result more than one.", K(hits.size()));
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_DEFAULT: {
|
|
return_val = error_val;
|
|
break;
|
|
}
|
|
case OB_JSON_ON_RESPONSE_NULL:
|
|
case OB_JSON_ON_RESPONSE_IMPLICIT: {
|
|
is_null_result = true;
|
|
break;
|
|
}
|
|
default: // error_type from get_on_empty_or_error has done range check, do nothing for default
|
|
break;
|
|
}
|
|
} else if (hits[0]->json_type() == ObJsonNodeType::J_NULL) {
|
|
is_null_result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// fill output
|
|
if (OB_UNLIKELY(OB_FAIL(ret))) {
|
|
if (is_cover_by_error) {
|
|
try_set_error_val<ObDatum>(res, ret, error_type, error_val);
|
|
}
|
|
LOG_WARN("json_values failed", K(ret));
|
|
} else if (is_null_result){
|
|
res.set_null();
|
|
} else {
|
|
if (return_val != NULL) {
|
|
res.set_datum(*return_val);
|
|
} else {
|
|
ObCollationType in_coll_type = expr.args_[0]->datum_meta_.cs_type_;
|
|
ObCollationType dst_coll_type = expr.datum_meta_.cs_type_;
|
|
ret = cast_to_res(&temp_allocator, expr, ctx, hits[0], error_type, error_val,
|
|
accuracy, dst_type, in_coll_type, dst_coll_type, res);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const
|
|
{
|
|
UNUSED(expr_cg_ctx);
|
|
UNUSED(raw_expr);
|
|
rt_expr.eval_func_ = eval_json_value;
|
|
return OB_SUCCESS;
|
|
}
|
|
|
|
template<typename Obj>
|
|
int ObExprJsonValue::check_default_val_accuracy(const ObAccuracy &accuracy,
|
|
const ObObjType &type,
|
|
const Obj *obj)
|
|
{
|
|
INIT_SUCC(ret);
|
|
ObObjTypeClass tc = ob_obj_type_class(type);
|
|
|
|
switch (tc) {
|
|
case ObNumberTC: {
|
|
number::ObNumber temp(obj->get_number());
|
|
ret = number_range_check(accuracy, NULL, temp, true);
|
|
break;
|
|
}
|
|
case ObDateTC: {
|
|
int32_t val = obj->get_date();
|
|
if (val == ObTimeConverter::ZERO_DATE) {
|
|
// check zero date for scale over mode
|
|
ret = OB_INVALID_DATE_VALUE;
|
|
LOG_WARN("Zero date is invalid for json_value", K(ret));
|
|
}
|
|
break;
|
|
}
|
|
case ObDateTimeTC: {
|
|
int64_t val = obj->get_datetime();
|
|
ret = datetime_scale_check(accuracy, val, true);
|
|
break;
|
|
}
|
|
case ObTimeTC: {
|
|
int64_t val = obj->get_time();
|
|
ret = time_scale_check(accuracy, val, true);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::get_accuracy_internal(ObAccuracy &accuracy,
|
|
ObObjType &dest_type,
|
|
const int64_t value,
|
|
const ObLengthSemantics &length_semantics)
|
|
{
|
|
INIT_SUCC(ret);
|
|
ParseNode node;
|
|
node.value_ = value;
|
|
dest_type = static_cast<ObObjType>(node.int16_values_[0]);
|
|
|
|
if (ObFloatType == dest_type) {
|
|
// boundaries already checked in calc result type
|
|
if (node.int16_values_[OB_NODE_CAST_N_PREC_IDX] > OB_MAX_FLOAT_PRECISION) {
|
|
dest_type = ObDoubleType;
|
|
}
|
|
}
|
|
ObObjTypeClass dest_tc = ob_obj_type_class(dest_type);
|
|
if (ObStringTC == dest_tc) {
|
|
// parser will abort all negative number
|
|
// if length < 0 means DEFAULT_STR_LENGTH or OUT_OF_STR_LEN.
|
|
accuracy.set_full_length(node.int32_values_[1], length_semantics,
|
|
lib::is_oracle_mode());
|
|
} else if (ObRawTC == dest_tc) {
|
|
accuracy.set_length(node.int32_values_[1]);
|
|
} else if(ObTextTC == dest_tc || ObJsonTC == dest_tc) {
|
|
accuracy.set_length(node.int32_values_[1] < 0 ?
|
|
ObAccuracy::DDL_DEFAULT_ACCURACY[dest_type].get_length() : node.int32_values_[1]);
|
|
} else if (ObIntervalTC == dest_tc) {
|
|
if (OB_UNLIKELY(!ObIntervalScaleUtil::scale_check(node.int16_values_[3]) ||
|
|
!ObIntervalScaleUtil::scale_check(node.int16_values_[2]))) {
|
|
ret = OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE;
|
|
LOG_WARN("Invalid scale.", K(ret), K(node.int16_values_[3]), K(node.int16_values_[2]));
|
|
} else {
|
|
ObScale scale = (dest_type == ObIntervalYMType) ?
|
|
ObIntervalScaleUtil::interval_ym_scale_to_ob_scale(
|
|
static_cast<int8_t>(node.int16_values_[3]))
|
|
: ObIntervalScaleUtil::interval_ds_scale_to_ob_scale(
|
|
static_cast<int8_t>(node.int16_values_[2]),
|
|
static_cast<int8_t>(node.int16_values_[3]));
|
|
accuracy.set_scale(scale);
|
|
}
|
|
} else {
|
|
const ObAccuracy &def_acc =
|
|
ObAccuracy::DDL_DEFAULT_ACCURACY2[lib::is_oracle_mode()][dest_type];
|
|
if (ObNumberType == dest_type && 0 == node.int16_values_[2]) {
|
|
accuracy.set_precision(def_acc.get_precision());
|
|
} else {
|
|
accuracy.set_precision(node.int16_values_[2]);
|
|
}
|
|
accuracy.set_scale(node.int16_values_[3]);
|
|
if (lib::is_oracle_mode() && ObDoubleType == dest_type) {
|
|
accuracy.set_accuracy(def_acc.get_precision());
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::get_accuracy(const ObExpr &expr,
|
|
ObEvalCtx &ctx,
|
|
ObAccuracy &accuracy,
|
|
ObObjType &dest_type,
|
|
bool &is_cover_by_error)
|
|
{
|
|
INIT_SUCC(ret);
|
|
ObDatum *dst_type_dat = NULL;
|
|
|
|
if (OB_ISNULL(expr.args_) || OB_ISNULL(expr.args_[2])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
is_cover_by_error = false;
|
|
LOG_WARN("unexpected expr", K(ret), K(expr.arg_cnt_), KP(expr.args_));
|
|
} else if (OB_FAIL(expr.args_[2]->eval(ctx, dst_type_dat))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval dst type datum failed", K(ret));
|
|
} else {
|
|
ret = get_accuracy_internal(accuracy,
|
|
dest_type,
|
|
dst_type_dat->get_int(),
|
|
expr.datum_meta_.length_semantics_);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::number_range_check(const ObAccuracy &accuracy,
|
|
ObIAllocator *allocator,
|
|
number::ObNumber &val,
|
|
bool strict)
|
|
{
|
|
INIT_SUCC(ret);
|
|
ObPrecision precision = accuracy.get_precision();
|
|
ObScale scale = accuracy.get_scale();
|
|
const number::ObNumber *min_check_num = NULL;
|
|
const number::ObNumber *max_check_num = NULL;
|
|
const number::ObNumber *min_num_mysql = NULL;
|
|
const number::ObNumber *max_num_mysql = NULL;
|
|
bool is_finish = false;
|
|
|
|
if (OB_UNLIKELY(precision < scale)) {
|
|
ret = OB_ERR_M_BIGGER_THAN_D;
|
|
LOG_WARN("Invalid accuracy.", K(ret), K(scale), K(precision));
|
|
} else if (number::ObNumber::MAX_PRECISION >= precision
|
|
&& precision >= OB_MIN_DECIMAL_PRECISION
|
|
&& number::ObNumber::MAX_SCALE >= scale
|
|
&& scale >= 0) {
|
|
min_check_num = &(ObNumberConstValue::MYSQL_CHECK_MIN[precision][scale]);
|
|
max_check_num = &(ObNumberConstValue::MYSQL_CHECK_MAX[precision][scale]);
|
|
min_num_mysql = &(ObNumberConstValue::MYSQL_MIN[precision][scale]);
|
|
max_num_mysql = &(ObNumberConstValue::MYSQL_MAX[precision][scale]);
|
|
} else {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_ISNULL(min_check_num) || OB_ISNULL(max_check_num)
|
|
|| (!lib::is_oracle_mode()
|
|
&& (OB_ISNULL(min_num_mysql) || OB_ISNULL(max_num_mysql)))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("min_num or max_num is null", K(ret), KPC(min_check_num), KPC(max_check_num));
|
|
} else if (val <= *min_check_num) {
|
|
if (lib::is_oracle_mode()) {
|
|
ret = OB_ERR_VALUE_LARGER_THAN_ALLOWED;
|
|
} else {
|
|
ret = OB_DATA_OUT_OF_RANGE;
|
|
}
|
|
LOG_WARN("val is out of min range check.", K(val), K(*min_check_num));
|
|
is_finish = true;
|
|
} else if (val >= *max_check_num) {
|
|
if (lib::is_oracle_mode()) {
|
|
ret = OB_ERR_VALUE_LARGER_THAN_ALLOWED;
|
|
} else {
|
|
ret = OB_DATA_OUT_OF_RANGE;
|
|
}
|
|
LOG_WARN("val is out of max range check.", K(val), K(*max_check_num));
|
|
is_finish = true;
|
|
} else {
|
|
ObNumStackOnceAlloc tmp_alloc;
|
|
number::ObNumber num;
|
|
if (OB_FAIL(num.from(val, tmp_alloc))) {
|
|
} else if (OB_FAIL(num.round(scale))) {
|
|
LOG_WARN("num.round failed", K(ret), K(scale));
|
|
} else {
|
|
if (strict) {
|
|
if (num.compare(val) != 0) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_WARN("input value is out of range.", K(scale), K(val));
|
|
} else {
|
|
is_finish = true;
|
|
}
|
|
} else {
|
|
if (OB_ISNULL(allocator)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("allocator is null", K(ret));
|
|
} else if (OB_FAIL(val.deep_copy_v3(num, *allocator))) {
|
|
LOG_WARN("val.deep_copy_v3 failed", K(ret), K(num));
|
|
} else {
|
|
is_finish = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && !is_finish) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected situation, res is not set", K(ret));
|
|
}
|
|
LOG_DEBUG("number_range_check_v2 done", K(ret), K(is_finish), K(accuracy), K(val),
|
|
KPC(min_check_num), KPC(max_check_num));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::datetime_scale_check(const ObAccuracy &accuracy,
|
|
int64_t &value,
|
|
bool strict)
|
|
{
|
|
INIT_SUCC(ret);
|
|
ObScale scale = accuracy.get_scale();
|
|
|
|
if (OB_UNLIKELY(scale > MAX_SCALE_FOR_TEMPORAL)) {
|
|
ret = OB_ERR_TOO_BIG_PRECISION;
|
|
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, "CAST",
|
|
static_cast<int64_t>(MAX_SCALE_FOR_TEMPORAL));
|
|
} else if (OB_UNLIKELY(0 <= scale && scale < MAX_SCALE_FOR_TEMPORAL)) {
|
|
// first check zero
|
|
if (strict &&
|
|
(value == ObTimeConverter::ZERO_DATE ||
|
|
value == ObTimeConverter::ZERO_DATETIME)) {
|
|
ret = OB_INVALID_DATE_VALUE;
|
|
LOG_WARN("Zero datetime is invalid in json_value.", K(value));
|
|
} else {
|
|
int64_t temp_value = value;
|
|
ObTimeConverter::round_datetime(scale, temp_value);
|
|
if (strict && temp_value != value) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_WARN("Invalid input value.", K(value), K(scale));
|
|
} else if (ObTimeConverter::is_valid_datetime(temp_value)) {
|
|
value = temp_value;
|
|
} else {
|
|
ret = OB_ERR_NULL_VALUE; // set null for res
|
|
LOG_DEBUG("Invalid datetime val, return set_null", K(temp_value));
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::time_scale_check(const ObAccuracy &accuracy, int64_t &value, bool strict)
|
|
{
|
|
INIT_SUCC(ret);
|
|
ObScale scale = accuracy.get_scale();
|
|
|
|
if (OB_LIKELY(0 <= scale && scale < MAX_SCALE_FOR_TEMPORAL)) {
|
|
int64_t temp_value = value;
|
|
ObTimeConverter::round_datetime(scale, temp_value);
|
|
if (strict && temp_value != value) { // round success
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_WARN("Invalid input value.", K(value), K(scale));
|
|
} else {
|
|
value = temp_value;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::get_cast_ret(int ret)
|
|
{
|
|
// compatibility for old ob
|
|
if (OB_UNLIKELY(OB_ERR_UNEXPECTED_TZ_TRANSITION == ret) ||
|
|
OB_UNLIKELY(OB_ERR_UNKNOWN_TIME_ZONE == ret)) {
|
|
ret = OB_INVALID_DATE_VALUE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_int(ObIJsonBase *j_base, ObObjType dst_type, int64_t &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_int(val, true))) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "SIGNED", "json_value");
|
|
LOG_WARN("cast to int failed", K(ret), K(*j_base));
|
|
} else if (dst_type < ObIntType &&
|
|
CAST_FAIL(int_range_check(dst_type, val, val))) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "SIGNED", "json_value");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_uint(ObIJsonBase *j_base, ObObjType dst_type, uint64_t &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_uint(val, true, true))) {
|
|
LOG_WARN("cast to uint failed", K(ret), K(*j_base));
|
|
if (ret == OB_OPERATE_OVERFLOW) {
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "UNSIGNED", "json_value");
|
|
}
|
|
} else if (dst_type < ObUInt64Type &&
|
|
CAST_FAIL(uint_upper_check(dst_type, val))) {
|
|
LOG_WARN("uint_upper_check failed", K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_datetime(ObIJsonBase *j_base,
|
|
common::ObAccuracy &accuracy,
|
|
int64_t &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_datetime(val))) {
|
|
LOG_WARN("wrapper to datetime failed.", K(ret), K(*j_base));
|
|
} else if (CAST_FAIL(datetime_scale_check(accuracy, val))) {
|
|
LOG_WARN("datetime_scale_check failed.", K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_otimstamp(ObIJsonBase *j_base,
|
|
const ObBasicSessionInfo *session,
|
|
common::ObAccuracy &accuracy,
|
|
ObObjType dst_type,
|
|
ObOTimestampData &out_val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
int64_t val;
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_datetime(val))) {
|
|
LOG_WARN("wrapper to datetime failed.", K(ret), K(*j_base));
|
|
} else {
|
|
if (session != NULL) {
|
|
const ObTimeZoneInfo *tz_info = session->get_timezone_info();
|
|
ObScale scale = accuracy.get_scale();
|
|
if (OB_FAIL(ObTimeConverter::odate_to_otimestamp(val, tz_info, dst_type, out_val))) {
|
|
LOG_WARN("fail to timestamp_to_timestamp_tz", K(ret), K(val), K(dst_type));
|
|
} else if (OB_UNLIKELY(0 <= scale && scale < MAX_SCALE_FOR_ORACLE_TEMPORAL)) {
|
|
ObOTimestampData ot_data = ObTimeConverter::round_otimestamp(scale, out_val);
|
|
if (ObTimeConverter::is_valid_otimestamp(ot_data.time_us_,
|
|
static_cast<int32_t>(ot_data.time_ctx_.tail_nsec_))) {
|
|
out_val = ot_data;
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid otimestamp, set it null ", K(ot_data), K(scale), "orig_date", out_val);
|
|
}
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("session is NULL", K(ret));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_date(ObIJsonBase *j_base, int32_t &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_date(val))) {
|
|
LOG_WARN("wrapper to date failed.", K(ret), K(*j_base));
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "DATE", "json_value");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_time(ObIJsonBase *j_base,
|
|
common::ObAccuracy &accuracy,
|
|
int64_t &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_time(val))) {
|
|
LOG_WARN("wrapper to time failed.", K(ret), K(*j_base));
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "TIME", "json_value");
|
|
} else if (CAST_FAIL(time_scale_check(accuracy, val))) {
|
|
LOG_WARN("time_scale_check failed.", K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_year(ObIJsonBase *j_base, uint8_t &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
// Compatible with mysql.
|
|
// There is no year type in json binary, it is store as a full int.
|
|
// For example, 1901 is stored as 1901, not 01.
|
|
// in mysql 8.0, json is converted to int first, then converted to year.
|
|
// However, json value returning as different behavior to cast expr.
|
|
int64_t int_val;
|
|
const uint16 min_year = 1901;
|
|
const uint16 max_year = 2155;
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_int(int_val))) {
|
|
LOG_WARN("wrapper to year failed.", K(ret), K(*j_base));
|
|
} else if (0 != int_val && (int_val < min_year || int_val > max_year)) {
|
|
// different with cast, if 0 < int val < 100, do not add base year
|
|
LOG_DEBUG("int out of year range", K(int_val));
|
|
ret = OB_DATA_OUT_OF_RANGE;
|
|
} else if(CAST_FAIL(ObTimeConverter::int_to_year(int_val, val))) {
|
|
LOG_WARN("int to year failed.", K(ret), K(int_val));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_float(ObIJsonBase *j_base, ObObjType dst_type, float &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
double tmp_val = 0;
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_double(tmp_val))) {
|
|
LOG_WARN("wrapper to date failed.", K(ret), K(*j_base));
|
|
} else {
|
|
val = static_cast<float>(tmp_val);
|
|
if (CAST_FAIL(real_range_check(dst_type, tmp_val, val))) {
|
|
LOG_WARN("real_range_check failed", K(ret), K(tmp_val));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_double(ObIJsonBase *j_base, ObObjType dst_type, double &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_double(val))) {
|
|
LOG_WARN("wrapper to date failed.", K(ret), K(*j_base));
|
|
} else if (ObUDoubleType == dst_type && CAST_FAIL(numeric_negative_check(val))) {
|
|
LOG_WARN("numeric_negative_check failed", K(ret), K(val));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_number(common::ObIAllocator *allocator,
|
|
ObIJsonBase *j_base,
|
|
common::ObAccuracy &accuracy,
|
|
ObObjType dst_type,
|
|
number::ObNumber &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_number(allocator, val))) {
|
|
LOG_WARN("fail to cast json as decimal", K(ret));
|
|
} else if (ObUNumberType == dst_type && CAST_FAIL(numeric_negative_check(val))) {
|
|
LOG_WARN("numeric_negative_check failed", K(ret), K(val));
|
|
} else if (CAST_FAIL(number_range_check(accuracy, allocator, val))) {
|
|
LOG_WARN("number_range_check failed", K(ret), K(val));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_string(common::ObIAllocator *allocator,
|
|
ObIJsonBase *j_base,
|
|
ObCollationType in_cs_type,
|
|
ObCollationType dst_cs_type,
|
|
common::ObAccuracy &accuracy,
|
|
ObObjType dst_type,
|
|
ObString &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (OB_ISNULL(allocator)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("allocator is null", K(ret));
|
|
} else {
|
|
ObJsonBuffer j_buf(allocator);
|
|
if (CAST_FAIL(j_base->print(j_buf, false))) {
|
|
LOG_WARN("fail to_string as json", K(ret));
|
|
} else {
|
|
ObObjType in_type = ObLongTextType;
|
|
ObString temp_str_val(j_buf.length(), j_buf.ptr());
|
|
bool is_need_string_string_convert = ((CS_TYPE_BINARY == dst_cs_type) ||
|
|
(ObCharset::charset_type_by_coll(in_cs_type) !=
|
|
ObCharset::charset_type_by_coll(dst_cs_type)));
|
|
if (is_need_string_string_convert) {
|
|
if (CS_TYPE_BINARY != in_cs_type
|
|
&& CS_TYPE_BINARY != dst_cs_type
|
|
&& (ObCharset::charset_type_by_coll(in_cs_type) !=
|
|
ObCharset::charset_type_by_coll(dst_cs_type))) {
|
|
char *buf = NULL;
|
|
const int64_t factor = 2;
|
|
int64_t buf_len = temp_str_val.length() * factor;
|
|
uint32_t result_len = 0;
|
|
buf = reinterpret_cast<char*>(allocator->alloc(buf_len));
|
|
if (OB_ISNULL(buf)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("alloc memory failed", K(ret));
|
|
} else if (OB_FAIL(ObCharset::charset_convert(in_cs_type, temp_str_val.ptr(),
|
|
temp_str_val.length(), dst_cs_type, buf,
|
|
buf_len, result_len))) {
|
|
LOG_WARN("charset convert failed", K(ret));
|
|
} else {
|
|
val.assign_ptr(buf, result_len);
|
|
}
|
|
} else {
|
|
if (CS_TYPE_BINARY == in_cs_type || CS_TYPE_BINARY == dst_cs_type) {
|
|
// just copy string when in_cs_type or out_cs_type is binary
|
|
const ObCharsetInfo *cs = NULL;
|
|
int64_t align_offset = 0;
|
|
if (CS_TYPE_BINARY == in_cs_type && lib::is_mysql_mode()
|
|
&& (NULL != (cs = ObCharset::get_charset(dst_cs_type)))) {
|
|
if (cs->mbminlen > 0 && temp_str_val.length() % cs->mbminlen != 0) {
|
|
align_offset = cs->mbminlen - temp_str_val.length() % cs->mbminlen;
|
|
}
|
|
}
|
|
int64_t len = align_offset + temp_str_val.length();
|
|
char *buf = reinterpret_cast<char*>(allocator->alloc(len));
|
|
if (OB_ISNULL(buf)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate memory failed", K(ret));
|
|
} else {
|
|
MEMMOVE(buf + align_offset, temp_str_val.ptr(), len - align_offset);
|
|
MEMSET(buf, 0, align_offset);
|
|
val.assign_ptr(buf, len);
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("same charset should not be here, just use cast_eval_arg", K(ret),
|
|
K(in_type), K(dst_type), K(in_cs_type), K(dst_cs_type));
|
|
}
|
|
}
|
|
} else {
|
|
val.assign_ptr(temp_str_val.ptr(), temp_str_val.length());
|
|
}
|
|
// do str length check
|
|
const int32_t str_len_char = static_cast<int32_t>(ObCharset::strlen_char(dst_cs_type,
|
|
val.ptr(), val.length()));
|
|
const ObLength max_accuracy_len = accuracy.get_length();
|
|
if (OB_SUCC(ret)) {
|
|
if (max_accuracy_len == DEFAULT_STR_LENGTH) { // default string len
|
|
} else if (max_accuracy_len <= 0 || str_len_char > max_accuracy_len) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "STRING", "json_value");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_bit(ObIJsonBase *j_base, uint64_t &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->to_bit(val))) {
|
|
LOG_WARN("fail get bit from json", K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_json(common::ObIAllocator *allocator,
|
|
ObIJsonBase *j_base, ObString &val)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_ISNULL(j_base)) {
|
|
ret = OB_ERR_NULL_VALUE;
|
|
LOG_WARN("json base is null", K(ret));
|
|
} else if (CAST_FAIL(j_base->get_raw_binary(val, allocator))) {
|
|
LOG_WARN("failed to get raw binary", K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_res(common::ObIAllocator *allocator,
|
|
ObExprCtx& expr_ctx,
|
|
ObIJsonBase *j_base,
|
|
uint8_t error_type,
|
|
ObObj *error_val,
|
|
common::ObAccuracy &accuracy,
|
|
ObObjType dst_type,
|
|
common::ObCollationType in_coll_type,
|
|
common::ObCollationType dst_coll_type,
|
|
common::ObCollationLevel dst_coll_level,
|
|
ObObj &res)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
switch (dst_type) {
|
|
case ObNullType : {
|
|
res.set_null();
|
|
break;
|
|
}
|
|
case ObTinyIntType:
|
|
case ObSmallIntType:
|
|
case ObMediumIntType:
|
|
case ObInt32Type:
|
|
case ObIntType: {
|
|
int64_t val = 0;
|
|
ret = cast_to_int(j_base, dst_type, val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_int(dst_type, val);
|
|
}
|
|
break;
|
|
}
|
|
case ObUTinyIntType:
|
|
case ObUSmallIntType:
|
|
case ObUMediumIntType:
|
|
case ObUInt32Type:
|
|
case ObUInt64Type: {
|
|
uint64_t val = 0;
|
|
ret = cast_to_uint(j_base, dst_type, val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_uint(dst_type, val);
|
|
}
|
|
break;
|
|
}
|
|
case ObDateTimeType: {
|
|
int64_t val = 0;
|
|
ret = cast_to_datetime(j_base, accuracy, val);
|
|
if (ret == OB_ERR_NULL_VALUE) {
|
|
res.set_null();
|
|
} else if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_datetime(dst_type, val);
|
|
}
|
|
break;
|
|
}
|
|
case ObTimestampType: {
|
|
const ObBasicSessionInfo *session = expr_ctx.my_session_;
|
|
ObOTimestampData val;
|
|
ret = cast_to_otimstamp(j_base, session, accuracy, dst_type, val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_otimestamp_value(dst_type, val);
|
|
}
|
|
break;
|
|
}
|
|
case ObDateType: {
|
|
int32_t val = 0;
|
|
ret = cast_to_date(j_base, val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_date(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObTimeType: {
|
|
int64_t val = 0;
|
|
ret = cast_to_time(j_base, accuracy, val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_time(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObYearType: {
|
|
uint8_t val = 0;
|
|
ret = cast_to_year(j_base, val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_year(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObFloatType:
|
|
case ObUFloatType: {
|
|
float out_val = 0;
|
|
ret = cast_to_float(j_base, dst_type, out_val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_float(dst_type, out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObDoubleType:
|
|
case ObUDoubleType: {
|
|
double out_val = 0;
|
|
ret = cast_to_double(j_base, dst_type, out_val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_double(dst_type, out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObUNumberType:
|
|
case ObNumberType: {
|
|
number::ObNumber out_val;
|
|
ret = cast_to_number(allocator, j_base, accuracy, dst_type, out_val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_number(dst_type, out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObVarcharType:
|
|
case ObCharType:
|
|
case ObTinyTextType:
|
|
case ObTextType :
|
|
case ObMediumTextType:
|
|
case ObHexStringType:
|
|
case ObLongTextType: {
|
|
ObString val;
|
|
ret = cast_to_string(allocator, j_base, in_coll_type, dst_coll_type, accuracy, dst_type, val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
// old engine set same alloctor for wrapper, so we can use val without copy
|
|
res.set_string(dst_type, val);
|
|
res.set_collation_type(dst_coll_type);
|
|
res.set_collation_level(dst_coll_level);
|
|
}
|
|
break;
|
|
}
|
|
case ObBitType: {
|
|
uint64_t out_val = 0;
|
|
ret = cast_to_bit(j_base, out_val);
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_bit(out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObJsonType: {
|
|
ObString out_val;
|
|
ret = cast_to_json(allocator, j_base, out_val);
|
|
if (OB_SUCC(ret)) {
|
|
char *buf = reinterpret_cast<char *>(expr_ctx.calc_buf_->alloc(out_val.length()));
|
|
if (OB_UNLIKELY(buf == NULL)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory for json array result", K(ret), K(out_val.length()));
|
|
} else {
|
|
MEMCPY(buf, out_val.ptr(), out_val.length());
|
|
out_val.assign_ptr(buf, out_val.length());
|
|
}
|
|
}
|
|
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
|
|
res.set_string(dst_type, out_val);
|
|
res.set_collation_type(dst_coll_type);
|
|
res.set_collation_level(dst_coll_level);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected dst_type", K(dst_type));
|
|
try_set_error_val<ObObj>(res, ret, error_type, error_val);
|
|
break;
|
|
}
|
|
}
|
|
LOG_DEBUG("finish cast_to_res.", K(ret), K(dst_type), K(error_type));
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::cast_to_res(common::ObIAllocator *allocator,
|
|
const ObExpr &expr,
|
|
ObEvalCtx &ctx,
|
|
ObIJsonBase *j_base,
|
|
uint8_t error_type,
|
|
ObDatum *error_val,
|
|
ObAccuracy &accuracy,
|
|
ObObjType dst_type,
|
|
ObCollationType in_coll_type,
|
|
ObCollationType dst_coll_type,
|
|
ObDatum &res)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
switch (dst_type) {
|
|
case ObNullType : {
|
|
res.set_null();
|
|
break;
|
|
}
|
|
case ObTinyIntType:
|
|
case ObSmallIntType:
|
|
case ObMediumIntType:
|
|
case ObInt32Type:
|
|
case ObIntType: {
|
|
int64_t val = 0;
|
|
ret = cast_to_int(j_base, dst_type, val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_int(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObUTinyIntType:
|
|
case ObUSmallIntType:
|
|
case ObUMediumIntType:
|
|
case ObUInt32Type:
|
|
case ObUInt64Type: {
|
|
uint64_t val = 0;
|
|
ret = cast_to_uint(j_base, dst_type, val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_uint(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObDateTimeType: {
|
|
int64_t val = 0;
|
|
ret = cast_to_datetime(j_base, accuracy, val);
|
|
if (ret == OB_ERR_NULL_VALUE) {
|
|
res.set_null();
|
|
} else if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_datetime(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObTimestampType: {
|
|
ObOTimestampData val;
|
|
GET_SESSION()
|
|
{
|
|
ret = cast_to_otimstamp(j_base, session, accuracy, dst_type, val);
|
|
}
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_otimestamp_tiny(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObDateType: {
|
|
int32_t val = 0;
|
|
ret = cast_to_date(j_base, val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_date(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObTimeType: {
|
|
int64_t val = 0;
|
|
ret = cast_to_time(j_base, accuracy, val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_time(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObYearType: {
|
|
uint8_t val = 0;
|
|
ret = cast_to_year(j_base, val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_year(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObFloatType:
|
|
case ObUFloatType: {
|
|
float out_val = 0;
|
|
ret = cast_to_float(j_base, dst_type, out_val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_float(out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObDoubleType:
|
|
case ObUDoubleType: {
|
|
double out_val = 0;
|
|
ret = cast_to_double(j_base, dst_type, out_val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_double(out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObUNumberType:
|
|
case ObNumberType: {
|
|
number::ObNumber out_val;
|
|
ret = cast_to_number(allocator, j_base, accuracy, dst_type, out_val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_number(out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObVarcharType:
|
|
case ObCharType:
|
|
case ObTinyTextType:
|
|
case ObTextType :
|
|
case ObMediumTextType:
|
|
case ObHexStringType:
|
|
case ObLongTextType: {
|
|
ObString val;
|
|
ret = cast_to_string(allocator, j_base, in_coll_type, dst_coll_type, accuracy, dst_type, val);
|
|
if (OB_SUCC(ret)) {
|
|
char *buf = expr.get_str_res_mem(ctx, val.length());
|
|
if (OB_ISNULL(buf)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate memory failed", K(ret));
|
|
} else {
|
|
MEMCPY(buf, val.ptr(), val.length());
|
|
val.assign_ptr(buf, val.length());
|
|
}
|
|
}
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
// old engine set same alloctor for wrapper, so we can use val without copy
|
|
res.set_string(val);
|
|
}
|
|
break;
|
|
}
|
|
case ObBitType: {
|
|
uint64_t out_val = 0;
|
|
ret = cast_to_bit(j_base, out_val);
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_bit(out_val);
|
|
}
|
|
break;
|
|
}
|
|
case ObJsonType: {
|
|
ObString out_val;
|
|
ret = cast_to_json(allocator, j_base, out_val);
|
|
if (OB_SUCC(ret)) {
|
|
char *buf = expr.get_str_res_mem(ctx, out_val.length());
|
|
if (OB_ISNULL(buf)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate memory failed", K(ret));
|
|
} else {
|
|
MEMCPY(buf, out_val.ptr(), out_val.length());
|
|
out_val.assign_ptr(buf, out_val.length());
|
|
}
|
|
}
|
|
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
|
|
res.set_string(out_val);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected dst_type", K(dst_type));
|
|
try_set_error_val<ObDatum>(res, ret, error_type, error_val);
|
|
break;
|
|
}
|
|
}
|
|
LOG_DEBUG("finish cast_to_res.", K(ret), K(dst_type), K(error_type));
|
|
|
|
return ret;
|
|
}
|
|
|
|
template<typename Obj>
|
|
bool ObExprJsonValue::try_set_error_val(Obj &res, int &ret, uint8_t error_type, Obj *error_val)
|
|
{
|
|
bool has_set_res = true;
|
|
|
|
if (OB_FAIL(ret)) {
|
|
if (error_type == OB_JSON_ON_RESPONSE_DEFAULT) {
|
|
set_val(res, error_val);
|
|
ret = OB_SUCCESS;
|
|
} else if (error_type == OB_JSON_ON_RESPONSE_NULL ||
|
|
error_type == OB_JSON_ON_RESPONSE_IMPLICIT) {
|
|
res.set_null();
|
|
ret = OB_SUCCESS;
|
|
}
|
|
} else {
|
|
has_set_res = false;
|
|
}
|
|
|
|
return has_set_res;
|
|
}
|
|
|
|
int ObExprJsonValue::get_on_empty_or_error_old(const ObObj *params,
|
|
ObExprCtx& expr_ctx,
|
|
const ObObjType dst_type,
|
|
uint8_t index,
|
|
bool &is_cover_by_error,
|
|
const ObAccuracy &accuracy,
|
|
uint8_t &type,
|
|
ObObj *default_value) const
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (OB_FAIL(param_eval(expr_ctx, params[index], index))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval json arg failed", K(ret));
|
|
} else {
|
|
ObObjType val_type = params[index].get_type();
|
|
if (val_type != ObIntType) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input type error", K(val_type));
|
|
} else {
|
|
int64_t option_type = params[index].get_int();
|
|
if (option_type < OB_JSON_ON_RESPONSE_ERROR ||
|
|
option_type > OB_JSON_ON_RESPONSE_IMPLICIT) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input option type error", K(option_type));
|
|
} else {
|
|
type = static_cast<uint8_t>(option_type);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
common::ObCastMode cast_mode = expr_ctx.cast_mode_;
|
|
expr_ctx.cast_mode_ &= ~CM_WARN_ON_FAIL; // make cast return error when fail
|
|
expr_ctx.cast_mode_ &= ~CM_NO_RANGE_CHECK; // make cast check range
|
|
expr_ctx.cast_mode_ &= ~CM_STRING_INTEGER_TRUNC; // make cast check range when string to uint
|
|
expr_ctx.cast_mode_ |= CM_ERROR_ON_SCALE_OVER; // make cast check presion and scale
|
|
expr_ctx.cast_mode_ |= CM_EXPLICIT_CAST; // make cast json fail return error
|
|
if (OB_FAIL(param_eval(expr_ctx, params[index + 1], index + 1))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval json arg failed", K(ret));
|
|
} else if (params[index + 1].get_type() == ObNullType || params[index + 1].is_null()) {
|
|
} else if (OB_FAIL(check_default_val_accuracy<ObObj>(accuracy, dst_type, &(params[index + 1])))) {
|
|
is_cover_by_error = false;
|
|
} else {
|
|
*default_value = params[index + 1];
|
|
}
|
|
if (ret == OB_OPERATE_OVERFLOW) {
|
|
if (dst_type >= ObDateTimeType && dst_type <= ObYearType) {
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "TIME DEFAULT", "json_value");
|
|
} else if (dst_type == ObNumberType || dst_type == ObUNumberType) {
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "DECIMAL DEFAULT", "json_value");
|
|
}
|
|
}
|
|
expr_ctx.cast_mode_ = cast_mode; // recover cast mode in old engine for cast mode used in global at expr
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::get_on_empty_or_error(const ObExpr &expr,
|
|
ObEvalCtx &ctx,
|
|
uint8_t index,
|
|
bool &is_cover_by_error,
|
|
const ObAccuracy &accuracy,
|
|
uint8_t &type,
|
|
ObDatum **default_value)
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
ObExpr *json_arg = expr.args_[index];
|
|
ObObjType val_type = json_arg->datum_meta_.type_;
|
|
ObDatum *json_datum = NULL;
|
|
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval json arg failed", K(ret));
|
|
} else if (val_type != ObIntType) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input type error", K(val_type));
|
|
} else {
|
|
int64_t option_type = json_datum->get_int();
|
|
if (option_type < OB_JSON_ON_RESPONSE_ERROR ||
|
|
option_type > OB_JSON_ON_RESPONSE_IMPLICIT) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("input option type error", K(option_type));
|
|
} else {
|
|
type = static_cast<uint8_t>(option_type);
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
json_arg = expr.args_[index + 1];
|
|
val_type = json_arg->datum_meta_.type_;
|
|
json_arg->extra_ &= ~CM_WARN_ON_FAIL; // make cast return error when fail
|
|
json_arg->extra_ &= ~CM_NO_RANGE_CHECK; // make cast check range
|
|
json_arg->extra_ &= ~CM_STRING_INTEGER_TRUNC; // make cast check range when string to uint
|
|
json_arg->extra_ |= CM_ERROR_ON_SCALE_OVER; // make cast check presion and scale
|
|
json_arg->extra_ |= CM_EXPLICIT_CAST; // make cast json fail return error
|
|
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
|
|
is_cover_by_error = false;
|
|
LOG_WARN("eval json arg failed", K(ret));
|
|
} else if (val_type == ObNullType || json_datum->is_null()) {
|
|
} else if (OB_FAIL(check_default_val_accuracy<ObDatum>(accuracy, val_type, json_datum))) {
|
|
is_cover_by_error = false;
|
|
} else {
|
|
*default_value = json_datum;
|
|
}
|
|
if (ret == OB_OPERATE_OVERFLOW) {
|
|
if (val_type >= ObDateTimeType && val_type <= ObYearType) {
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "TIME DEFAULT", "json_value");
|
|
} else if (val_type == ObNumberType || val_type == ObUNumberType) {
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "DECIMAL DEFAULT", "json_value");
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::get_cast_type(const ObExprResType param_type2, ObExprResType &dst_type) const
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (!param_type2.is_int() && !param_type2.get_param().is_int()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("cast param type is unexpected", K(param_type2));
|
|
} else {
|
|
const ObObj ¶m = param_type2.get_param();
|
|
ParseNode parse_node;
|
|
parse_node.value_ = param.get_int();
|
|
ObObjType obj_type = static_cast<ObObjType>(parse_node.int16_values_[OB_NODE_CAST_TYPE_IDX]);
|
|
dst_type.set_collation_type(static_cast<ObCollationType>(parse_node.int16_values_[OB_NODE_CAST_COLL_IDX]));
|
|
dst_type.set_type(obj_type);
|
|
if (ob_is_string_type(obj_type) || ob_is_lob_locator(obj_type)) {
|
|
// cast(x as char(10)) or cast(x as binary(10))
|
|
dst_type.set_full_length(parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX],
|
|
param_type2.get_accuracy().get_length_semantics());
|
|
} else if (ob_is_raw(obj_type)) {
|
|
dst_type.set_length(parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX]);
|
|
} else if (ObFloatType == dst_type.get_type()) {
|
|
// Compatible with mysql. If the precision p is not specified, produces a result of type FLOAT.
|
|
// If p is provided and 0 <= < p <= 24, the result is of type FLOAT. If 25 <= p <= 53,
|
|
// the result is of type DOUBLE. If p < 0 or p > 53, an error is returned
|
|
// however, ob use -1 as default precision, so it is a valid value
|
|
ObPrecision float_precision = parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX];
|
|
if (float_precision < -1 || float_precision > OB_MAX_DOUBLE_FLOAT_PRECISION) {
|
|
ret = OB_ERR_TOO_BIG_PRECISION;
|
|
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, float_precision, "CAST", OB_MAX_DOUBLE_FLOAT_PRECISION);
|
|
} else if (float_precision <= OB_MAX_FLOAT_PRECISION) {
|
|
dst_type.set_type(ObFloatType);
|
|
} else {
|
|
dst_type.set_type(ObDoubleType);
|
|
}
|
|
dst_type.set_precision(-1);
|
|
dst_type.set_scale(parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX]);
|
|
} else if (lib::is_mysql_mode() && ObJsonType == dst_type.get_type()) {
|
|
dst_type.set_collation_type(CS_TYPE_UTF8MB4_BIN);
|
|
} else {
|
|
dst_type.set_precision(parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX]);
|
|
dst_type.set_scale(parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX]);
|
|
}
|
|
LOG_DEBUG("get_cast_type", K(dst_type), K(param_type2));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::set_dest_type(ObExprResType &type1,
|
|
ObExprResType &type,
|
|
ObExprResType &dst_type,
|
|
ObExprTypeCtx &type_ctx) const
|
|
{
|
|
INIT_SUCC(ret);
|
|
const sql::ObSQLSessionInfo *session = type_ctx.get_session();
|
|
|
|
if (OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("ptr is NULL", K(ret), KP(session));
|
|
} else {
|
|
// always cast to user requested type
|
|
if (!lib::is_oracle_mode() &&
|
|
ObCharType == dst_type.get_type()) {
|
|
// cast(x as binary(10)), in parser,binary->T_CHAR+bianry, but, result type should be varchar, so set it.
|
|
type.set_type(ObVarcharType);
|
|
} else {
|
|
type.set_type(dst_type.get_type());
|
|
type.set_collation_type(dst_type.get_collation_type());
|
|
}
|
|
int16_t scale = dst_type.get_scale();
|
|
if (!lib::is_oracle_mode()
|
|
&& (ObTimeType == dst_type.get_type() || ObDateTimeType == dst_type.get_type())
|
|
&& scale > MAX_SCALE_FOR_TEMPORAL) {
|
|
ret = OB_ERR_TOO_BIG_PRECISION;
|
|
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, "CAST", OB_MAX_DATETIME_PRECISION);
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ObCompatibilityMode compatibility_mode = get_compatibility_mode();
|
|
ObCollationType collation_connection = type_ctx.get_coll_type();
|
|
ObCollationType collation_nation = session->get_nls_collation_nation();
|
|
int32_t length = 0;
|
|
if (ob_is_string_type(dst_type.get_type()) || ob_is_json(dst_type.get_type())) {
|
|
type.set_collation_level(CS_LEVEL_IMPLICIT);
|
|
int32_t len = dst_type.get_length();
|
|
int16_t length_semantics = ((dst_type.is_string_type())
|
|
? dst_type.get_length_semantics()
|
|
: (OB_NOT_NULL(type_ctx.get_session())
|
|
? type_ctx.get_session()->get_actual_nls_length_semantics()
|
|
: LS_BYTE));
|
|
if (len > 0) { // cast(1 as char(10))
|
|
type.set_full_length(len, length_semantics);
|
|
} else if (OB_FAIL(get_cast_string_len(type1, dst_type, type_ctx, len, length_semantics,
|
|
collation_connection))) { // cast (1 as char)
|
|
LOG_WARN("fail to get cast string length", K(ret));
|
|
} else {
|
|
type.set_full_length(len, length_semantics);
|
|
}
|
|
if (CS_TYPE_INVALID != dst_type.get_collation_type()) {
|
|
// cast as binary
|
|
type.set_collation_type(dst_type.get_collation_type());
|
|
} else {
|
|
// use collation of current session
|
|
type.set_collation_type(ob_is_nstring_type(dst_type.get_type()) ?
|
|
collation_nation : collation_connection);
|
|
}
|
|
} else {
|
|
type.set_length(length);
|
|
if (ObNumberTC == dst_type.get_type_class() && 0 == dst_type.get_precision()) {
|
|
// MySql:cast (1 as decimal(0)) = cast(1 as decimal)
|
|
// Oracle: cast(1.4 as number) = cast(1.4 as number(-1, -1))
|
|
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY2[compatibility_mode][ObNumberType].get_precision());
|
|
} else if (ObIntTC == dst_type.get_type_class() || ObUIntTC == dst_type.get_type_class()) {
|
|
// for int or uint , the precision = len
|
|
int32_t len = 0;
|
|
int16_t length_semantics = LS_BYTE;//unused
|
|
if (OB_FAIL(get_cast_inttc_len(type1, dst_type, type_ctx, len, length_semantics, collation_connection))) {
|
|
LOG_WARN("fail to get cast inttc length", K(ret));
|
|
} else {
|
|
len = len > OB_LITERAL_MAX_INT_LEN ? OB_LITERAL_MAX_INT_LEN : len;
|
|
type.set_precision(static_cast<int16_t>(len));
|
|
}
|
|
} else if (ORACLE_MODE == compatibility_mode && ObDoubleType == dst_type.get_type()) {
|
|
ObAccuracy acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[compatibility_mode][dst_type.get_type()];
|
|
type.set_accuracy(acc);
|
|
} else {
|
|
type.set_precision(dst_type.get_precision());
|
|
}
|
|
type.set_scale(dst_type.get_scale());
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::get_cast_string_len(ObExprResType &type1,
|
|
ObExprResType &type2,
|
|
ObExprTypeCtx &type_ctx,
|
|
int32_t &res_len,
|
|
int16_t &length_semantics,
|
|
ObCollationType conn) const
|
|
{
|
|
INIT_SUCC(ret);
|
|
const ObObj &val = type1.get_param();
|
|
|
|
if (!type1.is_literal()) { // column
|
|
res_len = CAST_STRING_DEFUALT_LENGTH[type1.get_type()];
|
|
int16_t prec = type1.get_accuracy().get_precision();
|
|
int16_t scale = type1.get_accuracy().get_scale();
|
|
switch(type1.get_type()) {
|
|
case ObTinyIntType:
|
|
case ObSmallIntType:
|
|
case ObMediumIntType:
|
|
case ObInt32Type:
|
|
case ObIntType:
|
|
case ObUTinyIntType:
|
|
case ObUSmallIntType:
|
|
case ObUMediumIntType:
|
|
case ObUInt32Type:
|
|
case ObUInt64Type: {
|
|
int32_t prec = static_cast<int32_t>(type1.get_accuracy().get_precision());
|
|
res_len = prec > res_len ? prec : res_len;
|
|
break;
|
|
}
|
|
case ObNumberType:
|
|
case ObUNumberType: {
|
|
if (lib::is_oracle_mode()) {
|
|
if (0 < prec) {
|
|
if (0 < scale) {
|
|
res_len = prec + 2;
|
|
} else if (0 == scale){
|
|
res_len = prec + 1;
|
|
} else {
|
|
res_len = prec - scale;
|
|
}
|
|
}
|
|
} else {
|
|
if (0 < prec) {
|
|
if (0 < scale) {
|
|
res_len = prec + 2;
|
|
} else {
|
|
res_len = prec + 1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ObTimestampTZType:
|
|
case ObTimestampLTZType:
|
|
case ObTimestampNanoType:
|
|
case ObDateTimeType:
|
|
case ObTimestampType: {
|
|
if (scale > 0) {
|
|
res_len += scale + 1;
|
|
}
|
|
break;
|
|
}
|
|
case ObTimeType: {
|
|
if (scale > 0) {
|
|
res_len += scale + 1;
|
|
}
|
|
break;
|
|
}
|
|
case ObTinyTextType:
|
|
case ObTextType:
|
|
case ObMediumTextType:
|
|
case ObLongTextType:
|
|
case ObVarcharType:
|
|
case ObCharType:
|
|
case ObHexStringType:
|
|
case ObRawType:
|
|
case ObNVarchar2Type:
|
|
case ObNCharType: {
|
|
res_len = type1.get_length();
|
|
length_semantics = type1.get_length_semantics();
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
} else if (type1.is_null()) {
|
|
res_len = 0;//compatible with mysql;
|
|
} else if (OB_ISNULL(type_ctx.get_session())) {
|
|
// calc type don't set ret, just print the log. by design.
|
|
LOG_WARN("my_session is null");
|
|
} else { // literal
|
|
ObArenaAllocator oballocator(ObModIds::BLOCK_ALLOC);
|
|
ObCastMode cast_mode = CM_NONE;
|
|
ObCollationType cast_coll_type = (CS_TYPE_INVALID != type2.get_collation_type())
|
|
? type2.get_collation_type()
|
|
: conn;
|
|
const ObDataTypeCastParams dtc_params =
|
|
ObBasicSessionInfo::create_dtc_params(type_ctx.get_session());
|
|
ObCastCtx cast_ctx(&oballocator,
|
|
&dtc_params,
|
|
0,
|
|
cast_mode,
|
|
cast_coll_type);
|
|
ObString val_str;
|
|
EXPR_GET_VARCHAR_V2(val, val_str);
|
|
if (OB_SUCC(ret) && NULL != val_str.ptr()) {
|
|
int32_t len_byte = val_str.length();
|
|
res_len = len_byte;
|
|
length_semantics = LS_CHAR;
|
|
if (NULL != val_str.ptr()) {
|
|
int32_t trunc_len_byte = static_cast<int32_t>(ObCharset::strlen_byte_no_sp(cast_coll_type,
|
|
val_str.ptr(), len_byte));
|
|
res_len = static_cast<int32_t>(ObCharset::strlen_char(cast_coll_type,
|
|
val_str.ptr(), trunc_len_byte));
|
|
}
|
|
if (type1.is_numeric_type() && !type1.is_integer_type()) {
|
|
res_len += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprJsonValue::get_cast_inttc_len(ObExprResType &type1,
|
|
ObExprResType &type2,
|
|
ObExprTypeCtx &type_ctx,
|
|
int32_t &res_len,
|
|
int16_t &length_semantics,
|
|
ObCollationType conn) const
|
|
{
|
|
INIT_SUCC(ret);
|
|
|
|
if (type1.is_literal()) { // literal
|
|
if (ObStringTC == type1.get_type_class()) {
|
|
res_len = type1.get_accuracy().get_length();
|
|
length_semantics = type1.get_length_semantics();
|
|
} else if (OB_FAIL(ObField::get_field_mb_length(type1.get_type(),
|
|
type1.get_accuracy(), type1.get_collation_type(), res_len))) {
|
|
LOG_WARN("failed to get filed mb length");
|
|
}
|
|
} else {
|
|
res_len = CAST_STRING_DEFUALT_LENGTH[type1.get_type()];
|
|
ObObjTypeClass tc1 = type1.get_type_class();
|
|
int16_t scale = type1.get_accuracy().get_scale();
|
|
if (ObDoubleTC == tc1) {
|
|
res_len -= 1;
|
|
} else if (ObDateTimeTC == tc1 && scale > 0) {
|
|
res_len += scale - 1;
|
|
} else if (OB_FAIL(get_cast_string_len(type1, type2, type_ctx, res_len, length_semantics, conn))) {
|
|
LOG_WARN("fail to get cast string length", K(ret));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
} |