From 313ab85aafec34fa2cc3b7de743187f1010f0a01 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Fri, 27 Nov 2020 07:46:58 +0800 Subject: [PATCH 01/19] fix different types compare error and query for bit --- ddl/ddl_api.go | 2 +- expression/builtin_cast.go | 2 +- expression/integration_test.go | 30 ++++++++++++++++++++++++ server/util.go | 42 ++++++++++++++++++++++++++++++++-- 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 3e1b3765fc073..e8b2d08d2ea73 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -534,7 +534,7 @@ func processColumnFlags(col *table.Column) { if col.Tp == mysql.TypeBit { // For BIT field, it's charset is binary but does not have binary flag. col.Flag &= ^mysql.BinaryFlag - col.Flag |= mysql.UnsignedFlag + //col.Flag |= mysql.UnsignedFlag } if col.Tp == mysql.TypeYear { // For Year field, it's charset is binary but does not have binary flag. diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index 5782e22a432d8..087866e050c66 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -1844,7 +1844,7 @@ func WrapWithCastAsDecimal(ctx sessionctx.Context, expr Expression) Expression { return expr } tp := types.NewFieldType(mysql.TypeNewDecimal) - tp.Flen, tp.Decimal = expr.GetType().Flen, expr.GetType().Decimal + //tp.Flen, tp.Decimal = expr.GetType().Flen, expr.GetType().Decimal if expr.GetType().EvalType() == types.ETInt { tp.Flen = mysql.MaxIntWidth } diff --git a/expression/integration_test.go b/expression/integration_test.go index c71986d7bec97..a5207ce4c80cb 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7761,6 +7761,36 @@ func (s *testIntegrationSuite) TestIssue17868(c *C) { tk.MustQuery("select col2 != 1 from t7").Check(testkit.Rows("1")) } +// for issue 20128 +func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { + collate.SetNewCollationEnabledForTest(true) + defer collate.SetNewCollationEnabledForTest(false) + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(b enum('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') DEFAULT NULL, c decimal(40,20));") + tk.MustExec("insert into t values('z', 19.18040000000000000000);") + tk.MustExec("insert into t values('z', 26.18040000000000000000);") + tk.MustExec("insert into t values('z', 25.18040000000000000000);") + tk.MustQuery("select * from t where t.b > t.c;").Check(testkit.Rows("z 19.18040000000000000000", "z 25.18040000000000000000")) + tk.MustQuery("select * from t where t.b < t.c;").Check(testkit.Rows("z 26.18040000000000000000")) + + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a bit(64), b double);") + tk.MustExec("insert into t values(-21172, -11623);") + tk.MustExec("insert into t values(0, 0);") + tk.MustExec("insert into t values(-1, -1);") + tk.MustExec("insert into t values(1, 1);") + tk.MustExec("insert into t (b)values(1);") + tk.MustQuery("select * from t order by a asc;").Check( + testkit.Rows( + "nil -11623", + "b'0' 0", + "b'1' 1", + "b'1111111111111111111111111111111111111111111111111010110101001100' -11623", + "b'1111111111111111111111111111111111111111111111111111111111111111' -1")) +} + func (s *testIntegrationSerialSuite) TestCollationIndexJoin(c *C) { collate.SetNewCollationEnabledForTest(true) defer collate.SetNewCollationEnabledForTest(false) diff --git a/server/util.go b/server/util.go index a5054b158720f..bcea6685969bd 100644 --- a/server/util.go +++ b/server/util.go @@ -230,6 +230,42 @@ func dumpBinaryDateTime(data []byte, t types.Time) []byte { return data } +func dumpLengthEncodedBit(buffer []byte, bytes []byte) []byte { + br := make([]byte, 0) + if len(bytes) > 0 { + br = append(br, 'b', '\'') + } + for i := 0; i < len(bytes); i++ { + bt := bytes[i] + if bt == 0 && len(br) == 2 { + continue + } + for j := 0; j < 8; j++ { + v := bt & 0x80 + if len(br) == 2 && v == 0 { + bt <<= 1 + continue + } + if v > 0 { + br = append(br, '1') + } else { + br = append(br, '0') + } + bt <<= 1 + } + } + + if len(br) >= 2 { + if len(br) == 2 { + br = append(br, '0') + } + br = append(br, '\'') + } + buffer = dumpLengthEncodedInt(buffer, uint64(len(br))) + buffer = append(buffer, br...) + return buffer +} + func dumpBinaryRow(buffer []byte, columns []*ColumnInfo, row chunk.Row) ([]byte, error) { buffer = append(buffer, mysql.OKHeader) nullBitmapOff := len(buffer) @@ -322,9 +358,11 @@ func dumpTextRow(buffer []byte, columns []*ColumnInfo, row chunk.Row) ([]byte, e buffer = dumpLengthEncodedString(buffer, tmp) case mysql.TypeNewDecimal: buffer = dumpLengthEncodedString(buffer, hack.Slice(row.GetMyDecimal(i).String())) - case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar, mysql.TypeBit, - mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob: + case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar, mysql.TypeTinyBlob, + mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob: buffer = dumpLengthEncodedString(buffer, row.GetBytes(i)) + case mysql.TypeBit: + buffer = dumpLengthEncodedBit(buffer, row.GetBytes(i)) case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp: buffer = dumpLengthEncodedString(buffer, hack.Slice(row.GetTime(i).String())) case mysql.TypeDuration: From 0ba309c092aeb23f0e0058237adb9e45f2d1bc42 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sat, 28 Nov 2020 11:41:34 +0800 Subject: [PATCH 02/19] fix test --- expression/integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/integration_test.go b/expression/integration_test.go index a5207ce4c80cb..290a94ebc556a 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7784,7 +7784,7 @@ func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { tk.MustExec("insert into t (b)values(1);") tk.MustQuery("select * from t order by a asc;").Check( testkit.Rows( - "nil -11623", + "nil 1", "b'0' 0", "b'1' 1", "b'1111111111111111111111111111111111111111111111111010110101001100' -11623", From 0664e07c67dd2db2aa035de79543f0ddf767e317 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sat, 28 Nov 2020 11:52:33 +0800 Subject: [PATCH 03/19] fix test --- expression/integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/integration_test.go b/expression/integration_test.go index 290a94ebc556a..309d63f87603c 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7784,7 +7784,7 @@ func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { tk.MustExec("insert into t (b)values(1);") tk.MustQuery("select * from t order by a asc;").Check( testkit.Rows( - "nil 1", + " 1", "b'0' 0", "b'1' 1", "b'1111111111111111111111111111111111111111111111111010110101001100' -11623", From 2431753dda8050a3df34d4fb419cfdaefe1f5326 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sat, 28 Nov 2020 20:59:43 +0800 Subject: [PATCH 04/19] fix test --- expression/integration_test.go | 12 +----------- server/util_test.go | 6 ++++++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/expression/integration_test.go b/expression/integration_test.go index 309d63f87603c..f53ac9cb8417b 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7778,17 +7778,7 @@ func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { tk.MustExec("drop table if exists t;") tk.MustExec("create table t(a bit(64), b double);") tk.MustExec("insert into t values(-21172, -11623);") - tk.MustExec("insert into t values(0, 0);") - tk.MustExec("insert into t values(-1, -1);") - tk.MustExec("insert into t values(1, 1);") - tk.MustExec("insert into t (b)values(1);") - tk.MustQuery("select * from t order by a asc;").Check( - testkit.Rows( - " 1", - "b'0' 0", - "b'1' 1", - "b'1111111111111111111111111111111111111111111111111010110101001100' -11623", - "b'1111111111111111111111111111111111111111111111111111111111111111' -1")) + tk.MustQuery("select b from t where a < b;").Check(testkit.Rows("-11623")) } func (s *testIntegrationSerialSuite) TestCollationIndexJoin(c *C) { diff --git a/server/util_test.go b/server/util_test.go index ff56a216c87df..d534610303a5b 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -228,6 +228,12 @@ func (s *testUtilSuite) TestDumpTextValue(c *C) { c.Assert(err, IsNil) c.Assert(mustDecodeStr(c, bs), Equals, "ename") + bit := types.NewMysqlBitDatum([]byte{255, 255, 255, 255, 255, 255, 255, 255}) + columns[0].Type = mysql.TypeBit + bs, err = dumpTextRow(nil, columns, chunk.MutRowFromDatums([]types.Datum{bit}).ToRow()) + c.Assert(err, IsNil) + c.Assert(mustDecodeStr(c, bs), Equals, "b'1111111111111111111111111111111111111111111111111111111111111111'") + set := types.Datum{} set.SetMysqlSet(types.Set{Name: "sname", Value: 0}, mysql.DefaultCollationName) columns[0].Type = mysql.TypeSet From 6ed6dcf76141b736518a7db1ffa040c74420ea8c Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sun, 29 Nov 2020 16:58:40 +0800 Subject: [PATCH 05/19] revert undignedFlag of typebit and evalReal not convert to uint when field's type is typebit --- ddl/ddl_api.go | 2 +- expression/builtin_cast.go | 4 ++-- expression/builtin_cast_vec.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index e8b2d08d2ea73..3e1b3765fc073 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -534,7 +534,7 @@ func processColumnFlags(col *table.Column) { if col.Tp == mysql.TypeBit { // For BIT field, it's charset is binary but does not have binary flag. col.Flag &= ^mysql.BinaryFlag - //col.Flag |= mysql.UnsignedFlag + col.Flag |= mysql.UnsignedFlag } if col.Tp == mysql.TypeYear { // For Year field, it's charset is binary but does not have binary flag. diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index 087866e050c66..2db116c5a2a87 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -485,7 +485,7 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b if isNull || err != nil { return res, isNull, err } - if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 { + if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && (!unsignedArgs0 || mysql.TypeBit == b.args[0].GetType().Tp) { res = float64(val) } else if b.inUnion && !unsignedArgs0 && val < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement @@ -1833,7 +1833,7 @@ func WrapWithCastAsReal(ctx sessionctx.Context, expr Expression) Expression { tp := types.NewFieldType(mysql.TypeDouble) tp.Flen, tp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength types.SetBinChsClnFlag(tp) - tp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag + //tp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag return BuildCastFunction(ctx, expr, tp) } diff --git a/expression/builtin_cast_vec.go b/expression/builtin_cast_vec.go index 40bab4d432af4..125cbbbb24fda 100644 --- a/expression/builtin_cast_vec.go +++ b/expression/builtin_cast_vec.go @@ -108,7 +108,7 @@ func (b *builtinCastIntAsRealSig) vecEvalReal(input *chunk.Chunk, result *chunk. if result.IsNull(i) { continue } - if !hasUnsignedFlag0 && !hasUnsignedFlag1 { + if !hasUnsignedFlag0 && (!hasUnsignedFlag1 || b.args[0].GetType().Tp == mysql.TypeBit) { rs[i] = float64(i64s[i]) } else if b.inUnion && !hasUnsignedFlag1 && i64s[i] < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement From 6968a16568af371b292e3da400977d0f80e9773e Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Tue, 1 Dec 2020 22:36:40 +0800 Subject: [PATCH 06/19] calc flag of result from cast function --- expression/builtin.go | 31 +++++++++++++++++++++++++++++++ expression/builtin_cast.go | 4 ++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index d632af718269c..178eaf2233942 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -148,6 +148,9 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return baseBuiltinFunc{}, errors.New("unexpected nil session ctx") } + orgArgs := make([]Expression, len(args)) + copy(orgArgs, args) + for i := range args { switch argTps[i] { case types.ETInt: @@ -167,6 +170,7 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex case types.ETJson: args[i] = WrapWithCastAsJSON(ctx, args[i]) } + generateRetFlag(args[i], argTps[i], orgArgs) } if err = checkIllegalMixCollation(funcName, args, retType); err != nil { @@ -255,6 +259,33 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return bf, nil } +func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) { + if len(args) < 2 { + return + } + var retType = res.GetType() + lhs, rhs := args[0], args[1] + if fun, ok := res.(*ScalarFunction); (ok && fun.FuncName.L == ast.Cast) || res.GetType().Tp == mysql.TypeBit { + if evalType == types.ETInt || evalType == types.ETReal { + lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag + if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { + if mysql.TypeBit == rhs.GetType().Tp { + lfg, rfg = rfg, lfg + } + if mysql.UnsignedFlag&rfg != 0 { + retType.Flag |= mysql.UnsignedFlag + } else { + retType.Flag &= ^mysql.UnsignedFlag + } + } + } else if evalType == types.ETDecimal && mysql.TypeEnum == lhs.GetType().Tp || mysql.TypeEnum == rhs.GetType().Tp { + if mysql.TypeNewDecimal == retType.Tp { + retType.Flen, retType.Decimal = types.UnspecifiedLength, types.UnspecifiedLength + } + } + } +} + // newBaseBuiltinFuncWithFieldType create BaseBuiltinFunc with FieldType charset and collation. // do not check and compute collation. func newBaseBuiltinFuncWithFieldType(ctx sessionctx.Context, tp *types.FieldType, args []Expression) (baseBuiltinFunc, error) { diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index 2db116c5a2a87..8dfed74e8731d 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -1833,7 +1833,7 @@ func WrapWithCastAsReal(ctx sessionctx.Context, expr Expression) Expression { tp := types.NewFieldType(mysql.TypeDouble) tp.Flen, tp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength types.SetBinChsClnFlag(tp) - //tp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag + tp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag return BuildCastFunction(ctx, expr, tp) } @@ -1844,7 +1844,7 @@ func WrapWithCastAsDecimal(ctx sessionctx.Context, expr Expression) Expression { return expr } tp := types.NewFieldType(mysql.TypeNewDecimal) - //tp.Flen, tp.Decimal = expr.GetType().Flen, expr.GetType().Decimal + tp.Flen, tp.Decimal = expr.GetType().Flen, expr.GetType().Decimal if expr.GetType().EvalType() == types.ETInt { tp.Flen = mysql.MaxIntWidth } From 849beff11519be5dca45db4f9638930178f88dbe Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Tue, 1 Dec 2020 23:10:57 +0800 Subject: [PATCH 07/19] fix --- expression/builtin.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index 178eaf2233942..d4989cb4e7880 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -269,13 +269,11 @@ func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) if evalType == types.ETInt || evalType == types.ETReal { lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { + retType.Flag |= mysql.UnsignedFlag if mysql.TypeBit == rhs.GetType().Tp { - lfg, rfg = rfg, lfg - } - if mysql.UnsignedFlag&rfg != 0 { - retType.Flag |= mysql.UnsignedFlag + retType.Flag &= ^(mysql.UnsignedFlag ^ lfg) } else { - retType.Flag &= ^mysql.UnsignedFlag + retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) } } } else if evalType == types.ETDecimal && mysql.TypeEnum == lhs.GetType().Tp || mysql.TypeEnum == rhs.GetType().Tp { From fd27373b138264acdbf7bfce281428db341519b2 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sat, 5 Dec 2020 11:37:45 +0800 Subject: [PATCH 08/19] revert change to check race test --- expression/builtin.go | 26 --------------------- expression/builtin_cast.go | 2 +- expression/builtin_cast_vec.go | 2 +- expression/integration_test.go | 20 ---------------- server/util.go | 42 ++-------------------------------- server/util_test.go | 6 ----- 6 files changed, 4 insertions(+), 94 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index d4989cb4e7880..ce4f62a5dedff 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -170,7 +170,6 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex case types.ETJson: args[i] = WrapWithCastAsJSON(ctx, args[i]) } - generateRetFlag(args[i], argTps[i], orgArgs) } if err = checkIllegalMixCollation(funcName, args, retType); err != nil { @@ -259,31 +258,6 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return bf, nil } -func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) { - if len(args) < 2 { - return - } - var retType = res.GetType() - lhs, rhs := args[0], args[1] - if fun, ok := res.(*ScalarFunction); (ok && fun.FuncName.L == ast.Cast) || res.GetType().Tp == mysql.TypeBit { - if evalType == types.ETInt || evalType == types.ETReal { - lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag - if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { - retType.Flag |= mysql.UnsignedFlag - if mysql.TypeBit == rhs.GetType().Tp { - retType.Flag &= ^(mysql.UnsignedFlag ^ lfg) - } else { - retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) - } - } - } else if evalType == types.ETDecimal && mysql.TypeEnum == lhs.GetType().Tp || mysql.TypeEnum == rhs.GetType().Tp { - if mysql.TypeNewDecimal == retType.Tp { - retType.Flen, retType.Decimal = types.UnspecifiedLength, types.UnspecifiedLength - } - } - } -} - // newBaseBuiltinFuncWithFieldType create BaseBuiltinFunc with FieldType charset and collation. // do not check and compute collation. func newBaseBuiltinFuncWithFieldType(ctx sessionctx.Context, tp *types.FieldType, args []Expression) (baseBuiltinFunc, error) { diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index 8dfed74e8731d..5782e22a432d8 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -485,7 +485,7 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b if isNull || err != nil { return res, isNull, err } - if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && (!unsignedArgs0 || mysql.TypeBit == b.args[0].GetType().Tp) { + if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 { res = float64(val) } else if b.inUnion && !unsignedArgs0 && val < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement diff --git a/expression/builtin_cast_vec.go b/expression/builtin_cast_vec.go index 125cbbbb24fda..40bab4d432af4 100644 --- a/expression/builtin_cast_vec.go +++ b/expression/builtin_cast_vec.go @@ -108,7 +108,7 @@ func (b *builtinCastIntAsRealSig) vecEvalReal(input *chunk.Chunk, result *chunk. if result.IsNull(i) { continue } - if !hasUnsignedFlag0 && (!hasUnsignedFlag1 || b.args[0].GetType().Tp == mysql.TypeBit) { + if !hasUnsignedFlag0 && !hasUnsignedFlag1 { rs[i] = float64(i64s[i]) } else if b.inUnion && !hasUnsignedFlag1 && i64s[i] < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement diff --git a/expression/integration_test.go b/expression/integration_test.go index ece322ce76126..85bd6fb3313bd 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7770,26 +7770,6 @@ func (s *testIntegrationSuite) TestIssue17868(c *C) { tk.MustQuery("select col2 != 1 from t7").Check(testkit.Rows("1")) } -// for issue 20128 -func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { - collate.SetNewCollationEnabledForTest(true) - defer collate.SetNewCollationEnabledForTest(false) - tk := testkit.NewTestKit(c, s.store) - tk.MustExec("use test") - tk.MustExec("drop table if exists t;") - tk.MustExec("create table t(b enum('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') DEFAULT NULL, c decimal(40,20));") - tk.MustExec("insert into t values('z', 19.18040000000000000000);") - tk.MustExec("insert into t values('z', 26.18040000000000000000);") - tk.MustExec("insert into t values('z', 25.18040000000000000000);") - tk.MustQuery("select * from t where t.b > t.c;").Check(testkit.Rows("z 19.18040000000000000000", "z 25.18040000000000000000")) - tk.MustQuery("select * from t where t.b < t.c;").Check(testkit.Rows("z 26.18040000000000000000")) - - tk.MustExec("drop table if exists t;") - tk.MustExec("create table t(a bit(64), b double);") - tk.MustExec("insert into t values(-21172, -11623);") - tk.MustQuery("select b from t where a < b;").Check(testkit.Rows("-11623")) -} - func (s *testIntegrationSerialSuite) TestCollationIndexJoin(c *C) { collate.SetNewCollationEnabledForTest(true) defer collate.SetNewCollationEnabledForTest(false) diff --git a/server/util.go b/server/util.go index bcea6685969bd..a5054b158720f 100644 --- a/server/util.go +++ b/server/util.go @@ -230,42 +230,6 @@ func dumpBinaryDateTime(data []byte, t types.Time) []byte { return data } -func dumpLengthEncodedBit(buffer []byte, bytes []byte) []byte { - br := make([]byte, 0) - if len(bytes) > 0 { - br = append(br, 'b', '\'') - } - for i := 0; i < len(bytes); i++ { - bt := bytes[i] - if bt == 0 && len(br) == 2 { - continue - } - for j := 0; j < 8; j++ { - v := bt & 0x80 - if len(br) == 2 && v == 0 { - bt <<= 1 - continue - } - if v > 0 { - br = append(br, '1') - } else { - br = append(br, '0') - } - bt <<= 1 - } - } - - if len(br) >= 2 { - if len(br) == 2 { - br = append(br, '0') - } - br = append(br, '\'') - } - buffer = dumpLengthEncodedInt(buffer, uint64(len(br))) - buffer = append(buffer, br...) - return buffer -} - func dumpBinaryRow(buffer []byte, columns []*ColumnInfo, row chunk.Row) ([]byte, error) { buffer = append(buffer, mysql.OKHeader) nullBitmapOff := len(buffer) @@ -358,11 +322,9 @@ func dumpTextRow(buffer []byte, columns []*ColumnInfo, row chunk.Row) ([]byte, e buffer = dumpLengthEncodedString(buffer, tmp) case mysql.TypeNewDecimal: buffer = dumpLengthEncodedString(buffer, hack.Slice(row.GetMyDecimal(i).String())) - case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar, mysql.TypeTinyBlob, - mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob: + case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar, mysql.TypeBit, + mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob: buffer = dumpLengthEncodedString(buffer, row.GetBytes(i)) - case mysql.TypeBit: - buffer = dumpLengthEncodedBit(buffer, row.GetBytes(i)) case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp: buffer = dumpLengthEncodedString(buffer, hack.Slice(row.GetTime(i).String())) case mysql.TypeDuration: diff --git a/server/util_test.go b/server/util_test.go index d534610303a5b..ff56a216c87df 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -228,12 +228,6 @@ func (s *testUtilSuite) TestDumpTextValue(c *C) { c.Assert(err, IsNil) c.Assert(mustDecodeStr(c, bs), Equals, "ename") - bit := types.NewMysqlBitDatum([]byte{255, 255, 255, 255, 255, 255, 255, 255}) - columns[0].Type = mysql.TypeBit - bs, err = dumpTextRow(nil, columns, chunk.MutRowFromDatums([]types.Datum{bit}).ToRow()) - c.Assert(err, IsNil) - c.Assert(mustDecodeStr(c, bs), Equals, "b'1111111111111111111111111111111111111111111111111111111111111111'") - set := types.Datum{} set.SetMysqlSet(types.Set{Name: "sname", Value: 0}, mysql.DefaultCollationName) columns[0].Type = mysql.TypeSet From 579cd4301dc36a3686f3e96fe3da97364a272c44 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sat, 5 Dec 2020 11:47:28 +0800 Subject: [PATCH 09/19] commit change by step --- expression/builtin.go | 26 ++++++++++++++++++++++++++ expression/builtin_cast.go | 2 +- expression/builtin_cast_vec.go | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index ce4f62a5dedff..d4989cb4e7880 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -170,6 +170,7 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex case types.ETJson: args[i] = WrapWithCastAsJSON(ctx, args[i]) } + generateRetFlag(args[i], argTps[i], orgArgs) } if err = checkIllegalMixCollation(funcName, args, retType); err != nil { @@ -258,6 +259,31 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return bf, nil } +func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) { + if len(args) < 2 { + return + } + var retType = res.GetType() + lhs, rhs := args[0], args[1] + if fun, ok := res.(*ScalarFunction); (ok && fun.FuncName.L == ast.Cast) || res.GetType().Tp == mysql.TypeBit { + if evalType == types.ETInt || evalType == types.ETReal { + lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag + if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { + retType.Flag |= mysql.UnsignedFlag + if mysql.TypeBit == rhs.GetType().Tp { + retType.Flag &= ^(mysql.UnsignedFlag ^ lfg) + } else { + retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) + } + } + } else if evalType == types.ETDecimal && mysql.TypeEnum == lhs.GetType().Tp || mysql.TypeEnum == rhs.GetType().Tp { + if mysql.TypeNewDecimal == retType.Tp { + retType.Flen, retType.Decimal = types.UnspecifiedLength, types.UnspecifiedLength + } + } + } +} + // newBaseBuiltinFuncWithFieldType create BaseBuiltinFunc with FieldType charset and collation. // do not check and compute collation. func newBaseBuiltinFuncWithFieldType(ctx sessionctx.Context, tp *types.FieldType, args []Expression) (baseBuiltinFunc, error) { diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index 5782e22a432d8..8dfed74e8731d 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -485,7 +485,7 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b if isNull || err != nil { return res, isNull, err } - if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 { + if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && (!unsignedArgs0 || mysql.TypeBit == b.args[0].GetType().Tp) { res = float64(val) } else if b.inUnion && !unsignedArgs0 && val < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement diff --git a/expression/builtin_cast_vec.go b/expression/builtin_cast_vec.go index 40bab4d432af4..125cbbbb24fda 100644 --- a/expression/builtin_cast_vec.go +++ b/expression/builtin_cast_vec.go @@ -108,7 +108,7 @@ func (b *builtinCastIntAsRealSig) vecEvalReal(input *chunk.Chunk, result *chunk. if result.IsNull(i) { continue } - if !hasUnsignedFlag0 && !hasUnsignedFlag1 { + if !hasUnsignedFlag0 && (!hasUnsignedFlag1 || b.args[0].GetType().Tp == mysql.TypeBit) { rs[i] = float64(i64s[i]) } else if b.inUnion && !hasUnsignedFlag1 && i64s[i] < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement From 6fba459e62f9085b282e1f2628b3a133dd780b0b Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sat, 5 Dec 2020 12:04:54 +0800 Subject: [PATCH 10/19] commit change by step --- expression/integration_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/expression/integration_test.go b/expression/integration_test.go index 85bd6fb3313bd..ece322ce76126 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -7770,6 +7770,26 @@ func (s *testIntegrationSuite) TestIssue17868(c *C) { tk.MustQuery("select col2 != 1 from t7").Check(testkit.Rows("1")) } +// for issue 20128 +func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { + collate.SetNewCollationEnabledForTest(true) + defer collate.SetNewCollationEnabledForTest(false) + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(b enum('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') DEFAULT NULL, c decimal(40,20));") + tk.MustExec("insert into t values('z', 19.18040000000000000000);") + tk.MustExec("insert into t values('z', 26.18040000000000000000);") + tk.MustExec("insert into t values('z', 25.18040000000000000000);") + tk.MustQuery("select * from t where t.b > t.c;").Check(testkit.Rows("z 19.18040000000000000000", "z 25.18040000000000000000")) + tk.MustQuery("select * from t where t.b < t.c;").Check(testkit.Rows("z 26.18040000000000000000")) + + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a bit(64), b double);") + tk.MustExec("insert into t values(-21172, -11623);") + tk.MustQuery("select b from t where a < b;").Check(testkit.Rows("-11623")) +} + func (s *testIntegrationSerialSuite) TestCollationIndexJoin(c *C) { collate.SetNewCollationEnabledForTest(true) defer collate.SetNewCollationEnabledForTest(false) From ba4cc4581b73a9e8fd70992155cc432e86facd8b Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Mon, 14 Dec 2020 23:53:53 +0800 Subject: [PATCH 11/19] add comment,fix bug --- expression/builtin.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/expression/builtin.go b/expression/builtin.go index d4989cb4e7880..b0d5a806de1c7 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -268,6 +268,7 @@ func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) if fun, ok := res.(*ScalarFunction); (ok && fun.FuncName.L == ast.Cast) || res.GetType().Tp == mysql.TypeBit { if evalType == types.ETInt || evalType == types.ETReal { lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag + // set signedFlag to 0 when bit convert explicitly or implicitly to int or real if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { retType.Flag |= mysql.UnsignedFlag if mysql.TypeBit == rhs.GetType().Tp { @@ -276,7 +277,9 @@ func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) } } - } else if evalType == types.ETDecimal && mysql.TypeEnum == lhs.GetType().Tp || mysql.TypeEnum == rhs.GetType().Tp { + } else if evalType == types.ETDecimal && (mysql.TypeEnum == lhs.GetType().Tp || mysql.TypeEnum == rhs.GetType().Tp) { + // set Flen and Decimal as unspecified length(-1) when the enum type is compare with decimal type,avoid loss of data, + // like the enum'z'(26), wher Flen=2,Decimal=2 the enum=26.00 but when Flen= 1,Decimal=2 the enum=9 if mysql.TypeNewDecimal == retType.Tp { retType.Flen, retType.Decimal = types.UnspecifiedLength, types.UnspecifiedLength } From cd6cea43648db374430cc6b79d5eef95f98a3415 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Tue, 15 Dec 2020 09:34:08 +0800 Subject: [PATCH 12/19] add test --- expression/integration_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/expression/integration_test.go b/expression/integration_test.go index 4a3cf222d0ca6..a2915253103ac 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -8257,3 +8257,23 @@ func (s *testIntegrationSuite) TestIssue12205(c *C) { tk.MustQuery("show warnings;").Check( testkit.Rows("Warning 1292 Truncated incorrect time value: '18446744072635875000'")) } + +// for issue 20128 +func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { + collate.SetNewCollationEnabledForTest(true) + defer collate.SetNewCollationEnabledForTest(false) + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(b enum('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') DEFAULT NULL, c decimal(40,20));") + tk.MustExec("insert into t values('z', 19.18040000000000000000);") + tk.MustExec("insert into t values('z', 26.18040000000000000000);") + tk.MustExec("insert into t values('z', 25.18040000000000000000);") + tk.MustQuery("select * from t where t.b > t.c;").Check(testkit.Rows("z 19.18040000000000000000", "z 25.18040000000000000000")) + tk.MustQuery("select * from t where t.b < t.c;").Check(testkit.Rows("z 26.18040000000000000000")) + + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a bit(64), b double);") + tk.MustExec("insert into t values(-21172, -11623);") + tk.MustQuery("select b from t where a < b;").Check(testkit.Rows("-11623")) +} From a29360ca22d57488d28356df33c9911bea8ea86c Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sun, 20 Dec 2020 01:47:19 +0800 Subject: [PATCH 13/19] when param type are decimal and enum retuen real type --- expression/builtin_compare.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index 5c73e0e070793..2ae2377e176a4 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1056,6 +1056,8 @@ func getBaseCmpType(lhs, rhs types.EvalType, lft, rft *types.FieldType) types.Ev return types.ETString } else if (lhs == types.ETInt || lft.Hybrid()) && (rhs == types.ETInt || rft.Hybrid()) { return types.ETInt + } else if lhs&rhs == types.ETDecimal&types.ETString { + return types.ETReal } else if ((lhs == types.ETInt || lft.Hybrid()) || lhs == types.ETDecimal) && ((rhs == types.ETInt || rft.Hybrid()) || rhs == types.ETDecimal) { return types.ETDecimal From 7a6c7303b481e906804f4068ed2ef01dc6874b61 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sun, 20 Dec 2020 11:39:29 +0800 Subject: [PATCH 14/19] fix --- expression/builtin_compare.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index 2ae2377e176a4..e897e73b894ca 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1056,7 +1056,7 @@ func getBaseCmpType(lhs, rhs types.EvalType, lft, rft *types.FieldType) types.Ev return types.ETString } else if (lhs == types.ETInt || lft.Hybrid()) && (rhs == types.ETInt || rft.Hybrid()) { return types.ETInt - } else if lhs&rhs == types.ETDecimal&types.ETString { + } else if (lhs == types.ETDecimal && rhs == types.ETString) || (lhs == types.ETString && rhs == types.ETDecimal) { return types.ETReal } else if ((lhs == types.ETInt || lft.Hybrid()) || lhs == types.ETDecimal) && ((rhs == types.ETInt || rft.Hybrid()) || rhs == types.ETDecimal) { From 9fcd1481edf0f89a2829b81d07f044caaafaa79d Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sun, 20 Dec 2020 11:48:47 +0800 Subject: [PATCH 15/19] fix --- expression/builtin.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index 676d18a2d02ae..8c0b6cc6fc993 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -280,12 +280,6 @@ func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) } } - } else if evalType == types.ETDecimal && (mysql.TypeEnum == lhs.GetType().Tp || mysql.TypeEnum == rhs.GetType().Tp) { - // set Flen and Decimal as unspecified length(-1) when the enum type is compare with decimal type,avoid loss of data, - // like the enum'z'(26), wher Flen=2,Decimal=2 the enum=26.00 but when Flen= 1,Decimal=2 the enum=9 - if mysql.TypeNewDecimal == retType.Tp { - retType.Flen, retType.Decimal = types.UnspecifiedLength, types.UnspecifiedLength - } } } } From 5d2d0c199e7e77b0b9ac4ac9965711e3158fc95b Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sun, 20 Dec 2020 18:03:23 +0800 Subject: [PATCH 16/19] fix --- expression/builtin.go | 26 -------------------------- expression/builtin_cast.go | 1 - expression/builtin_compare.go | 5 ----- 3 files changed, 32 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index 8c0b6cc6fc993..c64ef75b759ab 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -148,9 +148,6 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return baseBuiltinFunc{}, errors.New("unexpected nil session ctx") } - orgArgs := make([]Expression, len(args)) - copy(orgArgs, args) - for i := range args { switch argTps[i] { case types.ETInt: @@ -170,7 +167,6 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex case types.ETJson: args[i] = WrapWithCastAsJSON(ctx, args[i]) } - generateRetFlag(args[i], argTps[i], orgArgs) } if err = checkIllegalMixCollation(funcName, args, retType); err != nil { @@ -262,28 +258,6 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return bf, nil } -func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) { - if len(args) < 2 { - return - } - var retType = res.GetType() - lhs, rhs := args[0], args[1] - if fun, ok := res.(*ScalarFunction); (ok && fun.FuncName.L == ast.Cast) || res.GetType().Tp == mysql.TypeBit { - if evalType == types.ETInt || evalType == types.ETReal { - lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag - // set signedFlag to 0 when bit convert explicitly or implicitly to int or real - if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { - retType.Flag |= mysql.UnsignedFlag - if mysql.TypeBit == rhs.GetType().Tp { - retType.Flag &= ^(mysql.UnsignedFlag ^ lfg) - } else { - retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) - } - } - } - } -} - // newBaseBuiltinFuncWithFieldType create BaseBuiltinFunc with FieldType charset and collation. // do not check and compute collation. func newBaseBuiltinFuncWithFieldType(ctx sessionctx.Context, tp *types.FieldType, args []Expression) (baseBuiltinFunc, error) { diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index b724730556d80..a488978f1d090 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -1829,7 +1829,6 @@ func WrapWithCastAsReal(ctx sessionctx.Context, expr Expression) Expression { tp := types.NewFieldType(mysql.TypeDouble) tp.Flen, tp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength types.SetBinChsClnFlag(tp) - tp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag return BuildCastFunction(ctx, expr, tp) } diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index e897e73b894ca..69ca0c3781b0a 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1056,11 +1056,6 @@ func getBaseCmpType(lhs, rhs types.EvalType, lft, rft *types.FieldType) types.Ev return types.ETString } else if (lhs == types.ETInt || lft.Hybrid()) && (rhs == types.ETInt || rft.Hybrid()) { return types.ETInt - } else if (lhs == types.ETDecimal && rhs == types.ETString) || (lhs == types.ETString && rhs == types.ETDecimal) { - return types.ETReal - } else if ((lhs == types.ETInt || lft.Hybrid()) || lhs == types.ETDecimal) && - ((rhs == types.ETInt || rft.Hybrid()) || rhs == types.ETDecimal) { - return types.ETDecimal } return types.ETReal } From 671ab34712c696cbea44f41117711b6868e50fba Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Sun, 20 Dec 2020 22:38:57 +0800 Subject: [PATCH 17/19] revert --- expression/builtin.go | 26 ++++++++++++++++++++++++++ expression/builtin_cast.go | 1 + expression/builtin_compare.go | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/expression/builtin.go b/expression/builtin.go index c64ef75b759ab..0766405314b61 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -148,6 +148,9 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return baseBuiltinFunc{}, errors.New("unexpected nil session ctx") } + orgArgs := make([]Expression, len(args)) + copy(orgArgs, args) + for i := range args { switch argTps[i] { case types.ETInt: @@ -167,6 +170,7 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex case types.ETJson: args[i] = WrapWithCastAsJSON(ctx, args[i]) } + generateRetFlag(args[i], argTps[i], orgArgs) } if err = checkIllegalMixCollation(funcName, args, retType); err != nil { @@ -906,3 +910,25 @@ func GetBuiltinList() []string { sort.Strings(res) return res } + +func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) { + if len(args) < 2 { + return + } + var retType = res.GetType() + lhs, rhs := args[0], args[1] + if fun, ok := res.(*ScalarFunction); (ok && fun.FuncName.L == ast.Cast) || res.GetType().Tp == mysql.TypeBit { + if evalType == types.ETInt || evalType == types.ETReal { + lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag + // set signedFlag to 0 when bit convert explicitly or implicitly to int or real + if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { + retType.Flag |= mysql.UnsignedFlag + if mysql.TypeBit == rhs.GetType().Tp { + retType.Flag &= ^(mysql.UnsignedFlag ^ lfg) + } else { + retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) + } + } + } + } +} diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index a488978f1d090..b724730556d80 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -1829,6 +1829,7 @@ func WrapWithCastAsReal(ctx sessionctx.Context, expr Expression) Expression { tp := types.NewFieldType(mysql.TypeDouble) tp.Flen, tp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength types.SetBinChsClnFlag(tp) + tp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag return BuildCastFunction(ctx, expr, tp) } diff --git a/expression/builtin_compare.go b/expression/builtin_compare.go index 69ca0c3781b0a..e897e73b894ca 100644 --- a/expression/builtin_compare.go +++ b/expression/builtin_compare.go @@ -1056,6 +1056,11 @@ func getBaseCmpType(lhs, rhs types.EvalType, lft, rft *types.FieldType) types.Ev return types.ETString } else if (lhs == types.ETInt || lft.Hybrid()) && (rhs == types.ETInt || rft.Hybrid()) { return types.ETInt + } else if (lhs == types.ETDecimal && rhs == types.ETString) || (lhs == types.ETString && rhs == types.ETDecimal) { + return types.ETReal + } else if ((lhs == types.ETInt || lft.Hybrid()) || lhs == types.ETDecimal) && + ((rhs == types.ETInt || rft.Hybrid()) || rhs == types.ETDecimal) { + return types.ETDecimal } return types.ETReal } From 521d416c0cc4347e0d0ce9800818a858bda51261 Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Wed, 23 Dec 2020 00:22:29 +0800 Subject: [PATCH 18/19] remove bit compare suit --- expression/builtin.go | 26 -------------------------- expression/builtin_cast.go | 2 +- expression/builtin_cast_vec.go | 2 +- expression/integration_test.go | 5 ----- 4 files changed, 2 insertions(+), 33 deletions(-) diff --git a/expression/builtin.go b/expression/builtin.go index 0766405314b61..c64ef75b759ab 100644 --- a/expression/builtin.go +++ b/expression/builtin.go @@ -148,9 +148,6 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex return baseBuiltinFunc{}, errors.New("unexpected nil session ctx") } - orgArgs := make([]Expression, len(args)) - copy(orgArgs, args) - for i := range args { switch argTps[i] { case types.ETInt: @@ -170,7 +167,6 @@ func newBaseBuiltinFuncWithTp(ctx sessionctx.Context, funcName string, args []Ex case types.ETJson: args[i] = WrapWithCastAsJSON(ctx, args[i]) } - generateRetFlag(args[i], argTps[i], orgArgs) } if err = checkIllegalMixCollation(funcName, args, retType); err != nil { @@ -910,25 +906,3 @@ func GetBuiltinList() []string { sort.Strings(res) return res } - -func generateRetFlag(res Expression, evalType types.EvalType, args []Expression) { - if len(args) < 2 { - return - } - var retType = res.GetType() - lhs, rhs := args[0], args[1] - if fun, ok := res.(*ScalarFunction); (ok && fun.FuncName.L == ast.Cast) || res.GetType().Tp == mysql.TypeBit { - if evalType == types.ETInt || evalType == types.ETReal { - lfg, rfg := args[0].GetType().Flag, args[1].GetType().Flag - // set signedFlag to 0 when bit convert explicitly or implicitly to int or real - if mysql.TypeBit == lhs.GetType().Tp || mysql.TypeBit == rhs.GetType().Tp { - retType.Flag |= mysql.UnsignedFlag - if mysql.TypeBit == rhs.GetType().Tp { - retType.Flag &= ^(mysql.UnsignedFlag ^ lfg) - } else { - retType.Flag &= ^(mysql.UnsignedFlag ^ rfg) - } - } - } - } -} diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index b724730556d80..4f16aa60db002 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -485,7 +485,7 @@ func (b *builtinCastIntAsRealSig) evalReal(row chunk.Row) (res float64, isNull b if isNull || err != nil { return res, isNull, err } - if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && (!unsignedArgs0 || mysql.TypeBit == b.args[0].GetType().Tp) { + if unsignedArgs0 := mysql.HasUnsignedFlag(b.args[0].GetType().Flag); !mysql.HasUnsignedFlag(b.tp.Flag) && !unsignedArgs0 { res = float64(val) } else if b.inUnion && !unsignedArgs0 && val < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement diff --git a/expression/builtin_cast_vec.go b/expression/builtin_cast_vec.go index fb459a8d4aa74..47214e5a0f5af 100644 --- a/expression/builtin_cast_vec.go +++ b/expression/builtin_cast_vec.go @@ -108,7 +108,7 @@ func (b *builtinCastIntAsRealSig) vecEvalReal(input *chunk.Chunk, result *chunk. if result.IsNull(i) { continue } - if !hasUnsignedFlag0 && (!hasUnsignedFlag1 || b.args[0].GetType().Tp == mysql.TypeBit) { + if !hasUnsignedFlag0 && !hasUnsignedFlag1 { rs[i] = float64(i64s[i]) } else if b.inUnion && !hasUnsignedFlag1 && i64s[i] < 0 { // Round up to 0 if the value is negative but the expression eval type is unsigned in `UNION` statement diff --git a/expression/integration_test.go b/expression/integration_test.go index 6232599c7d0f7..b1ce6afd0c5bd 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -8306,11 +8306,6 @@ func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { tk.MustExec("insert into t values('z', 25.18040000000000000000);") tk.MustQuery("select * from t where t.b > t.c;").Check(testkit.Rows("z 19.18040000000000000000", "z 25.18040000000000000000")) tk.MustQuery("select * from t where t.b < t.c;").Check(testkit.Rows("z 26.18040000000000000000")) - - tk.MustExec("drop table if exists t;") - tk.MustExec("create table t(a bit(64), b double);") - tk.MustExec("insert into t values(-21172, -11623);") - tk.MustQuery("select b from t where a < b;").Check(testkit.Rows("-11623")) } func (s *testIntegrationSuite2) TestCastCoer(c *C) { From 8d0794c05ebcd9066a103b3e68ae05635da3400d Mon Sep 17 00:00:00 2001 From: AI-Login-is-already-taken <956308585@qq.com> Date: Wed, 23 Dec 2020 22:09:45 +0800 Subject: [PATCH 19/19] Remove useless code --- expression/integration_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/expression/integration_test.go b/expression/integration_test.go index b1ce6afd0c5bd..017e25639d724 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -8295,8 +8295,6 @@ func (s *testIntegrationSuite) TestIssue12205(c *C) { // for issue 20128 func (s *testIntegrationSerialSuite) TestIssue20128(c *C) { - collate.SetNewCollationEnabledForTest(true) - defer collate.SetNewCollationEnabledForTest(false) tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") tk.MustExec("drop table if exists t;")