diff --git a/pkg/executor/test/issuetest/executor_issue_test.go b/pkg/executor/test/issuetest/executor_issue_test.go index 40e3ba89e218e..b577aab7e9eec 100644 --- a/pkg/executor/test/issuetest/executor_issue_test.go +++ b/pkg/executor/test/issuetest/executor_issue_test.go @@ -92,6 +92,10 @@ func TestUnionIssue(t *testing.T) { tk.MustExec("drop table if exists t1, t2") tk.MustExec("create table t1 (id int);") tk.MustExec("create table t2 (id int, c int);") + // Issue56587 + tk.MustQuery("select quote(cast('abc' as char)) union all select '1'").Check(testkit.Rows("'abc'", "1")) + tk.MustQuery(`select elt(2, "1", cast('abc' as char)) union all select "12" where false`).Check(testkit.Rows("abc")) + tk.MustQuery(`select hex(cast('1' as char)) union all select '1';`).Check(testkit.Rows("31", "1")) testCases := []struct { sql string diff --git a/pkg/expression/builtin_string.go b/pkg/expression/builtin_string.go index f056267637b53..c23dbae5afa77 100644 --- a/pkg/expression/builtin_string.go +++ b/pkg/expression/builtin_string.go @@ -1703,21 +1703,28 @@ func (c *hexFunctionClass) getFunction(ctx BuildContext, args []Expression) (bui switch argTp { case types.ETString, types.ETDatetime, types.ETTimestamp, types.ETDuration, types.ETJson: bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETString) + bf.tp.SetFlen(types.UnspecifiedLength) if err != nil { return nil, err } - argFieldTp := args[0].GetType(ctx.GetEvalCtx()) + argLen := args[0].GetType(ctx.GetEvalCtx()).GetFlen() // Use UTF8MB4 as default. - bf.tp.SetFlen(argFieldTp.GetFlen() * 4 * 2) + if argLen != types.UnspecifiedLength { + bf.tp.SetFlen(argLen * 4 * 2) + } sig := &builtinHexStrArgSig{bf} sig.setPbCode(tipb.ScalarFuncSig_HexStrArg) return sig, nil case types.ETInt, types.ETReal, types.ETDecimal: bf, err := newBaseBuiltinFuncWithTp(ctx, c.funcName, args, types.ETString, types.ETInt) + bf.tp.SetFlen(types.UnspecifiedLength) if err != nil { return nil, err } - bf.tp.SetFlen(args[0].GetType(ctx.GetEvalCtx()).GetFlen() * 2) + argLen := args[0].GetType(ctx.GetEvalCtx()).GetFlen() + if argLen != types.UnspecifiedLength { + bf.tp.SetFlen(argLen * 2) + } charset, collate := ctx.GetCharsetInfo() bf.tp.SetCharset(charset) bf.tp.SetCollate(collate) @@ -3072,7 +3079,12 @@ func (c *quoteFunctionClass) getFunction(ctx BuildContext, args []Expression) (b return nil, err } SetBinFlagOrBinStr(args[0].GetType(ctx.GetEvalCtx()), bf.tp) - bf.tp.SetFlen(2*args[0].GetType(ctx.GetEvalCtx()).GetFlen() + 2) + flen := args[0].GetType(ctx.GetEvalCtx()).GetFlen() + newFlen := 2*flen + 2 + if flen == types.UnspecifiedLength { + newFlen = types.UnspecifiedLength + } + bf.tp.SetFlen(newFlen) if bf.tp.GetFlen() > mysql.MaxBlobWidth { bf.tp.SetFlen(mysql.MaxBlobWidth) } @@ -3201,7 +3213,8 @@ func (c *eltFunctionClass) getFunction(ctx BuildContext, args []Expression) (bui if types.IsBinaryStr(argType) { types.SetBinChsClnFlag(bf.tp) } - if argType.GetFlen() > bf.tp.GetFlen() { + flen := argType.GetFlen() + if flen == types.UnspecifiedLength || flen > bf.tp.GetFlen() { bf.tp.SetFlen(argType.GetFlen()) } } diff --git a/pkg/expression/typeinfer_test.go b/pkg/expression/typeinfer_test.go index 20b03f145bafa..6264056f8f2da 100644 --- a/pkg/expression/typeinfer_test.go +++ b/pkg/expression/typeinfer_test.go @@ -483,8 +483,8 @@ func (s *InferTypeSuite) createTestCase4StrFuncs() []typeInferTestCase { {"quote(c_int_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 42, types.UnspecifiedLength}, {"quote(c_bigint_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 42, types.UnspecifiedLength}, - {"quote(c_float_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 0, types.UnspecifiedLength}, - {"quote(c_double_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 0, types.UnspecifiedLength}, + {"quote(c_float_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, types.UnspecifiedLength, types.UnspecifiedLength}, + {"quote(c_double_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, types.UnspecifiedLength, types.UnspecifiedLength}, {"convert(c_double_d using utf8mb4)", mysql.TypeLongBlob, charset.CharsetUTF8MB4, 0, mysql.MaxBlobWidth, types.UnspecifiedLength}, {"convert(c_binary using utf8mb4)", mysql.TypeLongBlob, charset.CharsetUTF8MB4, 0, mysql.MaxBlobWidth, types.UnspecifiedLength},