diff --git a/src/sql/engine/expr/ob_expr_space.cpp b/src/sql/engine/expr/ob_expr_space.cpp index 8a9ac70f9..d7d3a3ae6 100644 --- a/src/sql/engine/expr/ob_expr_space.cpp +++ b/src/sql/engine/expr/ob_expr_space.cpp @@ -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; diff --git a/src/sql/engine/expr/ob_expr_space.h b/src/sql/engine/expr/ob_expr_space.h index 6ab7bd362..60ffb1067 100644 --- a/src/sql/engine/expr/ob_expr_space.h +++ b/src/sql/engine/expr/ob_expr_space.h @@ -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); }; diff --git a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_space.result b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_space.result index 0f31eac7e..93f40a2b3 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_space.result +++ b/tools/deploy/mysql_test/test_suite/static_engine/r/mysql/expr_space.result @@ -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; diff --git a/tools/deploy/mysql_test/test_suite/static_engine/t/expr_space.test b/tools/deploy/mysql_test/test_suite/static_engine/t/expr_space.test index 336c483a7..88f04df4a 100644 --- a/tools/deploy/mysql_test/test_suite/static_engine/t/expr_space.test +++ b/tools/deploy/mysql_test/test_suite/static_engine/t/expr_space.test @@ -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; \ No newline at end of file