From 39a1b436666851f62526b211cf7905aae478a17d Mon Sep 17 00:00:00 2001 From: wjHuang Date: Thu, 9 Sep 2021 11:04:38 +0800 Subject: [PATCH] *: fix some problems related to notNullFlag (#27697) --- expression/builtin_time.go | 2 ++ expression/integration_test.go | 13 +++++++ expression/typeinfer_test.go | 41 +++++++++++---------- planner/core/physical_plans.go | 2 +- server/column.go | 3 -- server/tidb_test.go | 65 ++++++++++++++++++++++++++++++---- tests/globalkilltest/go.sum | 1 + types/field_type.go | 3 ++ types/field_type_test.go | 64 ++++++++++++++++----------------- 9 files changed, 132 insertions(+), 62 deletions(-) diff --git a/expression/builtin_time.go b/expression/builtin_time.go index 3e460f478b03..aacac2c787ca 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -2036,6 +2036,8 @@ func (c *sysDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres return nil, err } bf.tp.Flen, bf.tp.Decimal = 19, 0 + // Illegal parameters have been filtered out in the parser, so the result is always not null. + bf.tp.Flag |= mysql.NotNullFlag var sig builtinFunc if len(args) == 1 { diff --git a/expression/integration_test.go b/expression/integration_test.go index 65a0268a20ad..be262653ae24 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -3117,6 +3117,19 @@ func (s *testIntegrationSuite2) TestBuiltin(c *C) { result.Check(testkit.Rows(" 4")) result = tk.MustQuery("select * from t where b = case when a is null then 4 when a = 'str5' then 7 else 9 end") result.Check(testkit.Rows(" 4")) + result = tk.MustQuery(`SELECT -Max(+23) * -+Cast(--10 AS SIGNED) * -CASE + WHEN 0 > 85 THEN NULL + WHEN NOT + CASE +55 + WHEN +( +82 ) + -89 * -69 THEN +Count(-88) + WHEN +CASE 57 + WHEN +89 THEN -89 * Count(*) + WHEN 17 THEN NULL + END THEN ( -10 ) + END IS NULL THEN NULL + ELSE 83 + 48 + END AS col0; `) + result.Check(testkit.Rows("-30130")) // return type of case when expr should not include NotNullFlag. issue-23036 tk.MustExec("drop table if exists t1") diff --git a/expression/typeinfer_test.go b/expression/typeinfer_test.go index 8c21a005c6ad..4d2f2b8e0e56 100644 --- a/expression/typeinfer_test.go +++ b/expression/typeinfer_test.go @@ -146,11 +146,11 @@ func (s *testInferTypeSuite) TestInferType(c *C) { c.Assert(err, IsNil, comment) tp := p.Schema().Columns[0].RetType - c.Assert(tp.Tp, Equals, tt.tp, comment) - c.Assert(tp.Charset, Equals, tt.chs, comment) - c.Assert(tp.Flag, Equals, tt.flag, comment) - c.Assert(tp.Flen, Equals, tt.flen, comment) - c.Assert(tp.Decimal, Equals, tt.decimal, comment) + c.Check(tp.Tp, Equals, tt.tp, comment) + c.Check(tp.Charset, Equals, tt.chs, comment) + c.Check(tp.Flag, Equals, tt.flag, comment) + c.Check(tp.Flen, Equals, tt.flen, comment) + c.Check(tp.Decimal, Equals, tt.decimal, comment) } } @@ -242,17 +242,18 @@ func (s *testInferTypeSuite) createTestCase4StrFuncs() []typeInferTestCase { {"CONCAT(c_binary, c_int_d)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 40, types.UnspecifiedLength}, {"CONCAT(c_bchar, c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, {"CONCAT(c_bchar, 0x80)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 23, types.UnspecifiedLength}, - {"CONCAT('T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, 4, types.UnspecifiedLength}, + {"CONCAT('T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 4, types.UnspecifiedLength}, {"CONCAT('T', 'i', 'DB', c_binary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 24, types.UnspecifiedLength}, - {"CONCAT_WS('-', 'T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, 7, types.UnspecifiedLength}, + {"CONCAT_WS('-', 'T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 7, types.UnspecifiedLength}, {"CONCAT_WS(',', 'TiDB', c_binary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 26, types.UnspecifiedLength}, + {"CONCAT(c_bchar, 0x80)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 23, types.UnspecifiedLength}, {"left(c_int_d, c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 20, types.UnspecifiedLength}, {"right(c_int_d, c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 20, types.UnspecifiedLength}, {"lower(c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 20, types.UnspecifiedLength}, {"lower(c_binary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 20, types.UnspecifiedLength}, {"upper(c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 20, types.UnspecifiedLength}, {"upper(c_binary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 20, types.UnspecifiedLength}, - {"replace(1234, 2, 55)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, 20, types.UnspecifiedLength}, + {"replace(1234, 2, 55)", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 20, types.UnspecifiedLength}, {"replace(c_binary, 1, 2)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 20, types.UnspecifiedLength}, {"to_base64(c_binary)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 28, types.UnspecifiedLength}, {"substr(c_int_d, c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 20, types.UnspecifiedLength}, @@ -274,7 +275,7 @@ func (s *testInferTypeSuite) createTestCase4StrFuncs() []typeInferTestCase { {"ascii(c_char)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 3, 0}, {"ord(c_char)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, {`c_int_d like 'abc%'`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.IsBooleanFlag, 1, 0}, - {"tidb_version()", mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, len(printer.GetTiDBInfo()), types.UnspecifiedLength}, + {"tidb_version()", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, len(printer.GetTiDBInfo()), types.UnspecifiedLength}, {"tidb_is_ddl_owner()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxIntWidth, 0}, {"password(c_char)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, mysql.PWDHashLen + 1, types.UnspecifiedLength}, {"elt(c_int_d, c_char, c_char, c_char)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 20, types.UnspecifiedLength}, @@ -538,7 +539,7 @@ func (s *testInferTypeSuite) createTestCase4MathFuncs() []typeInferTestCase { {"floor(c_time_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, {"floor(c_enum)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, {"floor(c_text_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, - {"floor(18446744073709551615)", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag | mysql.NotNullFlag, 20, 0}, + {"floor(18446744073709551615)", mysql.TypeLonglong, charset.CharsetBin, mysql.NotNullFlag | mysql.UnsignedFlag | mysql.BinaryFlag, 20, 0}, {"floor(18446744073709551615.1)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 22, 0}, {"ceil(c_int_d)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 11, 0}, @@ -556,7 +557,7 @@ func (s *testInferTypeSuite) createTestCase4MathFuncs() []typeInferTestCase { {"ceil(c_time_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, {"ceil(c_enum)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, {"ceil(c_text_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, - {"ceil(18446744073709551615)", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag | mysql.NotNullFlag, 20, 0}, + {"ceil(18446744073709551615)", mysql.TypeLonglong, charset.CharsetBin, mysql.NotNullFlag | mysql.UnsignedFlag | mysql.BinaryFlag, 20, 0}, {"ceil(18446744073709551615.1)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 22, 0}, {"ceiling(c_int_d)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 11, 0}, @@ -567,7 +568,7 @@ func (s *testInferTypeSuite) createTestCase4MathFuncs() []typeInferTestCase { {"ceiling(c_time_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, {"ceiling(c_enum)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, {"ceiling(c_text_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, 0}, - {"ceiling(18446744073709551615)", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag | mysql.NotNullFlag, 20, 0}, + {"ceiling(18446744073709551615)", mysql.TypeLonglong, charset.CharsetBin, mysql.NotNullFlag | mysql.UnsignedFlag | mysql.BinaryFlag, 20, 0}, {"ceiling(18446744073709551615.1)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 22, 0}, {"conv(c_char, c_int_d, c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 64, types.UnspecifiedLength}, @@ -740,6 +741,8 @@ func (s *testInferTypeSuite) createTestCase4ArithmeticFuncs() []typeInferTestCas {"c_double_d / c_decimal", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, types.UnspecifiedLength}, {"c_double_d / c_char", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, types.UnspecifiedLength}, {"c_double_d / c_enum", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, types.UnspecifiedLength}, + {"2/3", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 5, 4}, + {"-2/3", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 6, 4}, {"c_int_d DIV c_int_d", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0}, {"c_uint_d DIV c_uint_d", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag, mysql.MaxIntWidth, 0}, @@ -1197,14 +1200,14 @@ func (s *testInferTypeSuite) createTestCase4OtherFuncs() []typeInferTestCase { func (s *testInferTypeSuite) createTestCase4TimeFuncs() []typeInferTestCase { return []typeInferTestCase{ - {`time_format('150:02:28', '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, 44, types.UnspecifiedLength}, - {`time_format(123456, '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, 44, types.UnspecifiedLength}, + {`time_format('150:02:28', '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 44, types.UnspecifiedLength}, + {`time_format(123456, '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 44, types.UnspecifiedLength}, {`time_format('bad string', '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 44, types.UnspecifiedLength}, {`time_format(null, '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 44, types.UnspecifiedLength}, {`date_format(null, '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 44, types.UnspecifiedLength}, - {`date_format('2017-06-15', '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, 44, types.UnspecifiedLength}, - {`date_format(151113102019.12, '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0 | mysql.NotNullFlag, 44, types.UnspecifiedLength}, + {`date_format('2017-06-15', '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 44, types.UnspecifiedLength}, + {`date_format(151113102019.12, '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 44, types.UnspecifiedLength}, {"timestampadd(HOUR, c_int_d, c_timestamp_d)", mysql.TypeString, charset.CharsetUTF8MB4, 0, 19, types.UnspecifiedLength}, {"timestampadd(minute, c_double_d, c_timestamp_d)", mysql.TypeString, charset.CharsetUTF8MB4, 0, 19, types.UnspecifiedLength}, @@ -1698,10 +1701,10 @@ func (s *testInferTypeSuite) createTestCase4TimeFuncs() []typeInferTestCase { {"utc_time(6) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 15, 6}, {"utc_time(7) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 6}, - {"curdate() ", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"utc_date() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"curdate()", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"sysdate(4)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 19, 0}, {"current_date() ", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, - {"utc_date() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, - {"sysdate(4) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 19, 0}, {"date(c_int_d )", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, {"date(c_bigint_d )", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, diff --git a/planner/core/physical_plans.go b/planner/core/physical_plans.go index 97c49dc92777..f64e3dbd0d92 100644 --- a/planner/core/physical_plans.go +++ b/planner/core/physical_plans.go @@ -841,7 +841,7 @@ type PhysicalIndexJoin struct { IdxColLens []int // CompareFilters stores the filters for last column if those filters need to be evaluated during execution. // e.g. select * from t, t1 where t.a = t1.a and t.b > t1.b and t.b < t1.b+10 - // If there's index(t.a, t.b). All the filters can be used to construct index range but t.b > t1.b and t.b < t1.b=10 + // If there's index(t.a, t.b). All the filters can be used to construct index range but t.b > t1.b and t.b < t1.b+10 // need to be evaluated after we fetch the data of t1. // This struct stores them and evaluate them to ranges. CompareFilters *ColWithCmpFuncManager diff --git a/server/column.go b/server/column.go index 425e8d60b40e..621d24533b85 100644 --- a/server/column.go +++ b/server/column.go @@ -76,9 +76,6 @@ func dumpFlag(tp byte, flag uint16) uint16 { case mysql.TypeEnum: return flag | uint16(mysql.EnumFlag) default: - if mysql.HasBinaryFlag(uint(flag)) { - return flag | uint16(mysql.NotNullFlag) - } return flag } } diff --git a/server/tidb_test.go b/server/tidb_test.go index f4fc28f5d1c6..1b49b6774a68 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -1404,17 +1404,68 @@ func (ts *tidbTestSuite) TestSumAvg(c *C) { } func (ts *tidbTestSuite) TestNullFlag(c *C) { - // issue #9689 qctx, err := ts.tidbdrv.OpenCtx(uint64(0), 0, uint8(tmysql.DefaultCollationID), "test", nil) c.Assert(err, IsNil) ctx := context.Background() - rs, err := Execute(ctx, qctx, "select 1") - c.Assert(err, IsNil) - cols := rs.Columns() - c.Assert(len(cols), Equals, 1) - expectFlag := uint16(tmysql.NotNullFlag | tmysql.BinaryFlag) - c.Assert(dumpFlag(cols[0].Type, cols[0].Flag), Equals, expectFlag) + { + // issue #9689 + rs, err := Execute(ctx, qctx, "select 1") + c.Assert(err, IsNil) + cols := rs.Columns() + c.Assert(len(cols), Equals, 1) + expectFlag := uint16(tmysql.NotNullFlag | tmysql.BinaryFlag) + c.Assert(dumpFlag(cols[0].Type, cols[0].Flag), Equals, expectFlag) + } + + { + // issue #19025 + rs, err := Execute(ctx, qctx, "select convert('{}', JSON)") + c.Assert(err, IsNil) + cols := rs.Columns() + c.Assert(len(cols), Equals, 1) + expectFlag := uint16(tmysql.BinaryFlag) + c.Assert(dumpFlag(cols[0].Type, cols[0].Flag), Equals, expectFlag) + } + + { + // issue #18488 + _, err := Execute(ctx, qctx, "use test") + c.Assert(err, IsNil) + _, err = Execute(ctx, qctx, "CREATE TABLE `test` (`iD` bigint(20) NOT NULL, `INT_TEST` int(11) DEFAULT NULL);") + c.Assert(err, IsNil) + rs, err := Execute(ctx, qctx, `SELECT id + int_test as res FROM test GROUP BY res ORDER BY res;`) + c.Assert(err, IsNil) + cols := rs.Columns() + c.Assert(len(cols), Equals, 1) + expectFlag := uint16(tmysql.BinaryFlag) + c.Assert(dumpFlag(cols[0].Type, cols[0].Flag), Equals, expectFlag) + } + { + + rs, err := Execute(ctx, qctx, "select if(1, null, 1) ;") + c.Assert(err, IsNil) + cols := rs.Columns() + c.Assert(len(cols), Equals, 1) + expectFlag := uint16(tmysql.BinaryFlag) + c.Assert(dumpFlag(cols[0].Type, cols[0].Flag), Equals, expectFlag) + } + { + rs, err := Execute(ctx, qctx, "select CASE 1 WHEN 2 THEN 1 END ;") + c.Assert(err, IsNil) + cols := rs.Columns() + c.Assert(len(cols), Equals, 1) + expectFlag := uint16(tmysql.BinaryFlag) + c.Assert(dumpFlag(cols[0].Type, cols[0].Flag), Equals, expectFlag) + } + { + rs, err := Execute(ctx, qctx, "select NULL;") + c.Assert(err, IsNil) + cols := rs.Columns() + c.Assert(len(cols), Equals, 1) + expectFlag := uint16(tmysql.BinaryFlag) + c.Assert(dumpFlag(cols[0].Type, cols[0].Flag), Equals, expectFlag) + } } func (ts *tidbTestSuite) TestNO_DEFAULT_VALUEFlag(c *C) { diff --git a/tests/globalkilltest/go.sum b/tests/globalkilltest/go.sum index 52995e9b56d4..8c13845301ef 100644 --- a/tests/globalkilltest/go.sum +++ b/tests/globalkilltest/go.sum @@ -356,6 +356,7 @@ github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTw github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/errors v0.11.5-0.20200902104258-eba4f1d8f6de/go.mod h1:g4vx//d6VakjJ0mk7iLBlKA8LFavV/sAVINT/1PFxeQ= +github.com/pingcap/errors v0.11.5-0.20200917111840-a15ef68f753d h1:TH18wFO5Nq/zUQuWu9ms2urgZnLP69XJYiI2JZAkUGc= github.com/pingcap/errors v0.11.5-0.20200917111840-a15ef68f753d/go.mod h1:g4vx//d6VakjJ0mk7iLBlKA8LFavV/sAVINT/1PFxeQ= github.com/pingcap/errors v0.11.5-0.20210513014640-40f9a1999b3b h1:j9MP8ma4e75tckq11+n4EhB2xq0xwYNoxL8w9JTZRhs= github.com/pingcap/errors v0.11.5-0.20210513014640-40f9a1999b3b/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= diff --git a/types/field_type.go b/types/field_type.go index a5e042ac78ea..122ecd24c8a6 100644 --- a/types/field_type.go +++ b/types/field_type.go @@ -193,6 +193,9 @@ func hasVariantFieldLength(tp *FieldType) bool { // DefaultTypeForValue returns the default FieldType for the value. func DefaultTypeForValue(value interface{}, tp *FieldType, char string, collate string) { + if value != nil { + tp.Flag |= mysql.NotNullFlag + } switch x := value.(type) { case nil: tp.Tp = mysql.TypeNull diff --git a/types/field_type_test.go b/types/field_type_test.go index b084935f4030..d98e2c3f3dc5 100644 --- a/types/field_type_test.go +++ b/types/field_type_test.go @@ -171,41 +171,41 @@ func (s *testFieldTypeSuite) TestDefaultTypeForValue(c *C) { flag uint }{ {nil, mysql.TypeNull, 0, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {1, mysql.TypeLonglong, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {0, mysql.TypeLonglong, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {432, mysql.TypeLonglong, 3, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {4321, mysql.TypeLonglong, 4, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {1234567, mysql.TypeLonglong, 7, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {12345678, mysql.TypeLonglong, 8, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {12345678901234567, mysql.TypeLonglong, 17, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {-42, mysql.TypeLonglong, 3, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {uint64(1), mysql.TypeLonglong, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, - {uint64(123), mysql.TypeLonglong, 3, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, - {uint64(1234), mysql.TypeLonglong, 4, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, - {uint64(1234567), mysql.TypeLonglong, 7, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, - {uint64(12345678), mysql.TypeLonglong, 8, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, - {uint64(12345678901234567), mysql.TypeLonglong, 17, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, - {"abc", mysql.TypeVarString, 3, UnspecifiedLength, charset.CharsetUTF8MB4, charset.CollationUTF8MB4, 0}, - {1.1, mysql.TypeDouble, 3, -1, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {[]byte("abc"), mysql.TypeBlob, 3, UnspecifiedLength, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {HexLiteral{}, mysql.TypeVarString, 0, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, - {BitLiteral{}, mysql.TypeVarString, 0, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {NewTime(ZeroCoreTime, mysql.TypeDatetime, DefaultFsp), mysql.TypeDatetime, 19, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {NewTime(FromDate(2017, 12, 12, 12, 59, 59, 0), mysql.TypeDatetime, 3), mysql.TypeDatetime, 23, 3, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {Duration{}, mysql.TypeDuration, 8, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {&MyDecimal{}, mysql.TypeNewDecimal, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {Enum{Name: "a", Value: 1}, mysql.TypeEnum, 1, UnspecifiedLength, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, - {Set{Name: "a", Value: 1}, mysql.TypeSet, 1, UnspecifiedLength, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag}, + {1, mysql.TypeLonglong, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {0, mysql.TypeLonglong, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {432, mysql.TypeLonglong, 3, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {4321, mysql.TypeLonglong, 4, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {1234567, mysql.TypeLonglong, 7, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {12345678, mysql.TypeLonglong, 8, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {12345678901234567, mysql.TypeLonglong, 17, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {-42, mysql.TypeLonglong, 3, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {uint64(1), mysql.TypeLonglong, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag}, + {uint64(123), mysql.TypeLonglong, 3, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag}, + {uint64(1234), mysql.TypeLonglong, 4, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag}, + {uint64(1234567), mysql.TypeLonglong, 7, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag}, + {uint64(12345678), mysql.TypeLonglong, 8, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag}, + {uint64(12345678901234567), mysql.TypeLonglong, 17, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag}, + {"abc", mysql.TypeVarString, 3, UnspecifiedLength, charset.CharsetUTF8MB4, charset.CollationUTF8MB4, mysql.NotNullFlag}, + {1.1, mysql.TypeDouble, 3, -1, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {[]byte("abc"), mysql.TypeBlob, 3, UnspecifiedLength, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {HexLiteral{}, mysql.TypeVarString, 0, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag}, + {BitLiteral{}, mysql.TypeVarString, 0, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {NewTime(ZeroCoreTime, mysql.TypeDatetime, DefaultFsp), mysql.TypeDatetime, 19, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {NewTime(FromDate(2017, 12, 12, 12, 59, 59, 0), mysql.TypeDatetime, 3), mysql.TypeDatetime, 23, 3, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {Duration{}, mysql.TypeDuration, 8, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {&MyDecimal{}, mysql.TypeNewDecimal, 1, 0, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {Enum{Name: "a", Value: 1}, mysql.TypeEnum, 1, UnspecifiedLength, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, + {Set{Name: "a", Value: 1}, mysql.TypeSet, 1, UnspecifiedLength, charset.CharsetBin, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag}, } - for _, tt := range tests { + for i, tt := range tests { var ft FieldType DefaultTypeForValue(tt.value, &ft, mysql.DefaultCharset, mysql.DefaultCollationName) - c.Assert(ft.Tp, Equals, tt.tp, Commentf("%v %v", ft.Tp, tt.tp)) - c.Assert(ft.Flen, Equals, tt.flen, Commentf("%v %v", ft.Flen, tt.flen)) - c.Assert(ft.Charset, Equals, tt.charset, Commentf("%v %v", ft.Charset, tt.charset)) - c.Assert(ft.Decimal, Equals, tt.decimal, Commentf("%v %v", ft.Decimal, tt.decimal)) - c.Assert(ft.Collate, Equals, tt.collation, Commentf("%v %v", ft.Collate, tt.collation)) - c.Assert(ft.Flag, Equals, tt.flag, Commentf("%v %v", ft.Flag, tt.flag)) + c.Assert(ft.Tp, Equals, tt.tp, Commentf("%v %v %v", i, ft.Tp, tt.tp)) + c.Assert(ft.Flen, Equals, tt.flen, Commentf("%v %v %v", i, ft.Flen, tt.flen)) + c.Assert(ft.Charset, Equals, tt.charset, Commentf("%v %v %v", i, ft.Charset, tt.charset)) + c.Assert(ft.Decimal, Equals, tt.decimal, Commentf("%v %v %v", i, ft.Decimal, tt.decimal)) + c.Assert(ft.Collate, Equals, tt.collation, Commentf("%v %v %v", i, ft.Collate, tt.collation)) + c.Assert(ft.Flag, Equals, tt.flag, Commentf("%v %v %v", i, ft.Flag, tt.flag)) } }