[CP] fix multiple type inferences with different result type when space expr input argument is string literal

This commit is contained in:
shadowao 2024-11-11 07:14:03 +00:00 committed by ob-robot
parent acba5dcdcd
commit c673714910
4 changed files with 137 additions and 13 deletions

View File

@ -35,25 +35,38 @@ inline int ObExprSpace::calc_result_type1(
ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
ObRawExpr * raw_expr = nullptr;
ObRawExpr * child_raw_expr = nullptr;
// space is mysql only expr
CK(lib::is_mysql_mode());
ObObjType res_type = ObMaxType;
if (type1.is_null() || (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_4_2_0_0)) {
res_type = ObVarcharType;
} else if (type1.is_literal()) {
const ObObj &obj = type1.get_param();
ObArenaAllocator alloc(ObModIds::OB_SQL_RES_TYPE);
const ObDataTypeCastParams dtc_params = type_ctx.get_dtc_params();
int64_t cur_time = 0;
ObCastMode cast_mode = CM_NONE;
if (FALSE_IT(ObSQLUtils::get_default_cast_mode(type_ctx.get_sql_mode(), cast_mode))) {
} else {
cast_mode |= CM_WARN_ON_FAIL;
ObCastCtx cast_ctx(
&alloc, &dtc_params, cur_time, cast_mode, CS_TYPE_INVALID);
int64_t count_val = 0;
EXPR_GET_INT64_V2(obj, count_val);
res_type = get_result_type_mysql(count_val);
if (OB_FAIL(calc_result_type(type_ctx, type1.get_param(), res_type))) {
LOG_WARN("calc_result_type fail", K(ret), K(type1), K(type_ctx));
}
} else if (OB_ISNULL(raw_expr = type_ctx.get_raw_expr())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("raw_expr is null", K(ret), K(type_ctx));
} else if (OB_ISNULL(child_raw_expr = raw_expr->get_param_expr(0))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("get child expr fail", K(ret), KPC(raw_expr), K(type_ctx));
} else if (T_FUN_SYS_CAST == child_raw_expr->get_expr_type()
&& child_raw_expr->has_flag(IS_OP_OPERAND_IMPLICIT_CAST)
&& child_raw_expr->get_param_expr(0)->get_result_type().is_literal()) {
// some scenarios may have multiple type inferences
// if the input is a string literal, the first inference will add an implicit cast to convert a string to an integer
// this makes the input type not literal in the second type inference, resulting in an inference to longtext
// this in turn causes multiple implicit cast to be added to the same expr
// so need to make a special judgment here
// eg :
// create table space_t1(c1 char(181) default (space( '1')));
// select c1 from space_t1;
if (child_raw_expr->get_param_expr(0)->get_result_type().is_null()) {
res_type = ObVarcharType;
} else if (OB_FAIL(calc_result_type(type_ctx, child_raw_expr->get_param_expr(0)->get_result_type().get_param(), res_type))) {
LOG_WARN("calc_result_type fail", K(ret), K(type1), K(type_ctx));
}
} else {
res_type = ObLongTextType;
@ -80,6 +93,26 @@ inline int ObExprSpace::calc_result_type1(
return ret;
}
int ObExprSpace::calc_result_type(ObExprTypeCtx &type_ctx, const ObObj &obj, ObObjType &res_type) const
{
int ret = OB_SUCCESS;
ObArenaAllocator alloc(ObModIds::OB_SQL_RES_TYPE);
const ObDataTypeCastParams dtc_params = type_ctx.get_dtc_params();
int64_t cur_time = 0;
ObCastMode cast_mode = CM_NONE;
// void return function
ObSQLUtils::get_default_cast_mode(type_ctx.get_sql_mode(), cast_mode);
cast_mode |= CM_WARN_ON_FAIL;
ObCastCtx cast_ctx(
&alloc, &dtc_params, cur_time, cast_mode, CS_TYPE_INVALID);
int64_t count_val = 0;
EXPR_GET_INT64_V2(obj, count_val);
if (OB_SUCC(ret)) {
res_type = get_result_type_mysql(count_val);
}
return ret;
}
int ObExprSpace::cg_expr(ObExprCGCtx &, const ObRawExpr &, ObExpr &rt_expr) const
{
int ret = OB_SUCCESS;

View File

@ -37,6 +37,8 @@ public:
static int eval_space(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum);
DECLARE_SET_LOCAL_SESSION_VARS;
private:
int calc_result_type(ObExprTypeCtx &type_ctx, const ObObj &obj, ObObjType &res_type) const;
DISALLOW_COPY_AND_ASSIGN(ObExprSpace);
};

View File

@ -92,3 +92,61 @@ select * from t1 where space(c1) = '';
drop table if exists t1;
drop database if exists luofan;
drop table if exists space_t1;
drop table if exists space_t2;
create table space_t1(c1 char(181) default (space( '1')), c2 int);
select * from space_t1;
+------+------+
| c1 | c2 |
+------+------+
+------+------+
insert into space_t1(c2) values(1);
select * from space_t1;
+------+------+
| c1 | c2 |
+------+------+
| | 1 |
+------+------+
create table space_t2 as select space('1') as c1 from space_t1;
desc space_t2;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| c1 | varchar(512) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
drop table space_t2;
create table space_t2 as select space('1024') as c1 from space_t1;
desc space_t2;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| c1 | text | YES | | NULL | |
+-------+------+------+-----+---------+-------+
drop table space_t2;
create table space_t2 as select space(NULL) as c1 from space_t1;
desc space_t2;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| c1 | varchar(512) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
drop table space_t2;
drop table space_t1;
create table space_t1(c1 char(181) default (space(NULL)), c2 int);
select * from space_t1;
+------+------+
| c1 | c2 |
+------+------+
+------+------+
insert into space_t1(c2) values(1);
select * from space_t1;
+------+------+
| c1 | c2 |
+------+------+
| NULL | 1 |
+------+------+
drop table space_t1;

View File

@ -64,3 +64,34 @@ drop database if exists luofan;
--enable_warnings
--disable_warnings
drop table if exists space_t1;
drop table if exists space_t2;
--enable_warnings
create table space_t1(c1 char(181) default (space( '1')), c2 int);
select * from space_t1;
insert into space_t1(c2) values(1);
select * from space_t1;
create table space_t2 as select space('1') as c1 from space_t1;
# c1 is varchar type
desc space_t2;
drop table space_t2;
create table space_t2 as select space('1024') as c1 from space_t1;
# c1 is text type
desc space_t2;
drop table space_t2;
create table space_t2 as select space(NULL) as c1 from space_t1;
# c1 is varchar type
desc space_t2;
drop table space_t2;
drop table space_t1;
create table space_t1(c1 char(181) default (space(NULL)), c2 int);
select * from space_t1;
insert into space_t1(c2) values(1);
select * from space_t1;
drop table space_t1;