From 2520d553a0d9e7db92bd0b43f83a926225b0ca0c Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Thu, 6 Aug 2020 11:42:48 +0800 Subject: [PATCH 1/9] fix that JSON type having an unexpected NOT_NULL flag --- expression/builtin_time.go | 2 + expression/constant.go | 31 ++++- expression/typeinfer_test.go | 228 ++++++++++++++++----------------- planner/core/physical_plans.go | 2 +- server/column.go | 3 - server/tidb_test.go | 26 +++- types/field_type.go | 3 + types/field_type_test.go | 50 ++++---- 8 files changed, 188 insertions(+), 157 deletions(-) diff --git a/expression/builtin_time.go b/expression/builtin_time.go index 92d0fdfe67722..6cf268868d36f 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -2030,6 +2030,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/constant.go b/expression/constant.go index da8aceea95159..8a4f1694e324d 100644 --- a/expression/constant.go +++ b/expression/constant.go @@ -15,6 +15,7 @@ package expression import ( "fmt" + "sync" "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/terror" @@ -52,7 +53,9 @@ func NewNull() *Constant { // Constant stands for a constant value. type Constant struct { - Value types.Datum + Value types.Datum + // once protects the changes of RetType + once sync.Once RetType *types.FieldType // DeferredExpr holds deferred function in PlanCache cached plan. // it's only used to represent non-deterministic functions(see expression.DeferredFunctions) @@ -66,6 +69,20 @@ type Constant struct { collationInfo } +// Clone implements Expression interface. +func (c *Constant) Clone() Expression { + con := &Constant{ + Value: c.Value, + once: sync.Once{}, + RetType: c.RetType, + DeferredExpr: c.DeferredExpr, + ParamMarker: c.ParamMarker, + hashcode: c.hashcode, + collationInfo: c.collationInfo, + } + return con +} + // ParamMarker indicates param provided by COM_STMT_EXECUTE. type ParamMarker struct { ctx sessionctx.Context @@ -94,12 +111,6 @@ func (c *Constant) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf("\"%s\"", c)), nil } -// Clone implements Expression interface. -func (c *Constant) Clone() Expression { - con := *c - return &con -} - // GetType implements Expression interface. func (c *Constant) GetType() *types.FieldType { if c.ParamMarker != nil { @@ -110,6 +121,12 @@ func (c *Constant) GetType() *types.FieldType { types.DefaultParamTypeForValue(dt.GetValue(), tp) return tp } + if !c.Value.IsNull() { + c.once.Do(func() { + c.RetType = c.RetType.Clone() + c.RetType.Flag |= mysql.NotNullFlag + }) + } return c.RetType } diff --git a/expression/typeinfer_test.go b/expression/typeinfer_test.go index 69346addc7822..0dfc2d876f490 100644 --- a/expression/typeinfer_test.go +++ b/expression/typeinfer_test.go @@ -146,36 +146,36 @@ 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) } } func (s *testInferTypeSuite) createTestCase4Constants() []typeInferTestCase { return []typeInferTestCase{ - {"1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, - {"-1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 2, 0}, - {"1.23", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 4, 2}, - {"-1.23", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 5, 2}, - {"123e5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, 8, types.UnspecifiedLength}, - {"-123e5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, 9, types.UnspecifiedLength}, - {"123e-5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, 7, types.UnspecifiedLength}, - {"-123e-5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, 8, types.UnspecifiedLength}, + {"1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1, 0}, + {"-1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 2, 0}, + {"1.23", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 4, 2}, + {"-1.23", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 5, 2}, + {"123e5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 8, types.UnspecifiedLength}, + {"-123e5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 9, types.UnspecifiedLength}, + {"123e-5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 7, types.UnspecifiedLength}, + {"-123e-5", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 8, types.UnspecifiedLength}, {"NULL", mysql.TypeNull, charset.CharsetBin, mysql.BinaryFlag, 0, 0}, - {"TRUE", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.IsBooleanFlag, 1, 0}, - {"FALSE", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.IsBooleanFlag, 1, 0}, - {"'1234'", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 4, types.UnspecifiedLength}, - {"_utf8'1234'", mysql.TypeVarString, charset.CharsetUTF8, 0, 4, types.UnspecifiedLength}, - {"_binary'1234'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 4, types.UnspecifiedLength}, - {"b'0001'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, - {"b'000100001'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 2, 0}, - {"b'0000000000010000'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 2, 0}, - {"x'10'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, 3, 0}, - {"x'ff10'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, 6, 0}, - {"x'0000000000000000ff10'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, 30, 0}, + {"TRUE", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.IsBooleanFlag | mysql.NotNullFlag, 1, 0}, + {"FALSE", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.IsBooleanFlag | mysql.NotNullFlag, 1, 0}, + {"'1234'", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 4, types.UnspecifiedLength}, + {"_utf8'1234'", mysql.TypeVarString, charset.CharsetUTF8, mysql.NotNullFlag, 4, types.UnspecifiedLength}, + {"_binary'1234'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 4, types.UnspecifiedLength}, + {"b'0001'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1, 0}, + {"b'000100001'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 2, 0}, + {"b'0000000000010000'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 2, 0}, + {"x'10'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag, 3, 0}, + {"x'ff10'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag, 6, 0}, + {"x'0000000000000000ff10'", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag, 30, 0}, } } @@ -241,9 +241,9 @@ func (s *testInferTypeSuite) createTestCase4StrFuncs() []typeInferTestCase { {"space(c_int_d)", mysql.TypeLongBlob, mysql.DefaultCharset, 0, mysql.MaxBlobWidth, types.UnspecifiedLength}, {"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, mysql.BinaryFlag, 40, types.UnspecifiedLength}, - {"CONCAT('T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 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, 6, types.UnspecifiedLength}, + {"CONCAT_WS('-', 'T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 6, types.UnspecifiedLength}, {"CONCAT_WS(',', 'TiDB', c_binary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 25, 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}, @@ -251,7 +251,7 @@ func (s *testInferTypeSuite) createTestCase4StrFuncs() []typeInferTestCase { {"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, 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}, @@ -273,8 +273,8 @@ 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, 1, 0}, - {"tidb_version()", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, len(printer.GetTiDBInfo()), types.UnspecifiedLength}, - {"tidb_is_ddl_owner()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0}, + {"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}, {"elt(c_int_d, c_char, c_char, c_binary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 20, types.UnspecifiedLength}, @@ -291,11 +291,11 @@ func (s *testInferTypeSuite) createTestCase4StrFuncs() []typeInferTestCase { {"locate(c_binary, c_char, c_int_d)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0}, {"locate(c_binary, c_binary, c_int_d)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0}, - {"lpad('TiDB', 12, 'go' )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 48, types.UnspecifiedLength}, + {"lpad('TiDB', 12, 'go' )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 48, types.UnspecifiedLength}, {"lpad(c_binary, 12, 'go' )", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 12, types.UnspecifiedLength}, {"lpad(c_char, c_int_d, c_binary)", mysql.TypeLongBlob, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxBlobWidth, types.UnspecifiedLength}, {"lpad(c_char, c_int_d, c_char )", mysql.TypeLongBlob, charset.CharsetUTF8MB4, 0, mysql.MaxBlobWidth, types.UnspecifiedLength}, - {"rpad('TiDB', 12, 'go' )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 48, types.UnspecifiedLength}, + {"rpad('TiDB', 12, 'go' )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 48, types.UnspecifiedLength}, {"rpad(c_binary, 12, 'go' )", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 12, types.UnspecifiedLength}, {"rpad(c_char, c_int_d, c_binary)", mysql.TypeLongBlob, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxBlobWidth, types.UnspecifiedLength}, {"rpad(c_char, c_int_d, c_char )", mysql.TypeLongBlob, charset.CharsetUTF8MB4, 0, mysql.MaxBlobWidth, types.UnspecifiedLength}, @@ -493,7 +493,7 @@ func (s *testInferTypeSuite) createTestCase4MathFuncs() []typeInferTestCase { {"exp(c_time_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, types.UnspecifiedLength}, {"exp(c_timestamp_d)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, types.UnspecifiedLength}, {"exp(c_binary)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxRealWidth, types.UnspecifiedLength}, - {"pi()", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag, 8, 6}, + {"pi()", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 8, 6}, {"~c_int_d", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, mysql.MaxIntWidth, 0}, {"!c_int_d", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, {"c_int_d & c_int_d", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, mysql.MaxIntWidth, 0}, @@ -535,8 +535,8 @@ 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.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 20, 0}, - {"floor(18446744073709551615.1)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 22, 0}, + {"floor(18446744073709551615)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 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}, {"ceil(c_uint_d)", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag, 10, 0}, @@ -553,8 +553,8 @@ 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.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 20, 0}, - {"ceil(18446744073709551615.1)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 22, 0}, + {"ceil(18446744073709551615)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 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}, {"ceiling(c_decimal)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 6, 0}, @@ -564,8 +564,8 @@ 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.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 20, 0}, - {"ceiling(18446744073709551615.1)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 22, 0}, + {"ceiling(18446744073709551615)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 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}, {"conv(c_int_d, c_int_d, c_int_d)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 64, types.UnspecifiedLength}, @@ -841,15 +841,15 @@ func (s *testInferTypeSuite) createTestCase4Aggregations() []typeInferTestCase { func (s *testInferTypeSuite) createTestCase4InfoFunc() []typeInferTestCase { return []typeInferTestCase{ - {"last_insert_id( )", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, mysql.MaxIntWidth, 0}, + {"last_insert_id( )", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag, mysql.MaxIntWidth, 0}, {"last_insert_id(c_int_d)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, mysql.MaxIntWidth, 0}, {"found_rows()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, mysql.MaxIntWidth, 0}, - {"database()", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 64, types.UnspecifiedLength}, + {"database()", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 64, types.UnspecifiedLength}, {"current_user()", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 64, types.UnspecifiedLength}, - {"current_role()", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 64, types.UnspecifiedLength}, + {"current_role()", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 64, types.UnspecifiedLength}, {"user()", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 64, types.UnspecifiedLength}, - {"connection_id()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag, mysql.MaxIntWidth, 0}, - {"version()", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 64, types.UnspecifiedLength}, + {"connection_id()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag | mysql.NotNullFlag, mysql.MaxIntWidth, 0}, + {"version()", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 64, types.UnspecifiedLength}, } } @@ -871,8 +871,8 @@ func (s *testInferTypeSuite) createTestCase4EncryptionFuncs() []typeInferTestCas {"md5(c_blob_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 32, types.UnspecifiedLength}, {"md5(c_set )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 32, types.UnspecifiedLength}, {"md5(c_enum )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 32, types.UnspecifiedLength}, - {"md5('1234' )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 32, types.UnspecifiedLength}, - {"md5(1234 )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 32, types.UnspecifiedLength}, + {"md5('1234' )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 32, types.UnspecifiedLength}, + {"md5(1234 )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 32, types.UnspecifiedLength}, {"sha(c_int_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, {"sha(c_bigint_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, @@ -890,8 +890,8 @@ func (s *testInferTypeSuite) createTestCase4EncryptionFuncs() []typeInferTestCas {"sha(c_blob_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, {"sha(c_set )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, {"sha(c_enum )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, - {"sha('1234' )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, - {"sha(1234 )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, + {"sha('1234' )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 40, types.UnspecifiedLength}, + {"sha(1234 )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 40, types.UnspecifiedLength}, {"sha1(c_int_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, {"sha1(c_bigint_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, @@ -909,8 +909,8 @@ func (s *testInferTypeSuite) createTestCase4EncryptionFuncs() []typeInferTestCas {"sha1(c_blob_d )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, {"sha1(c_set )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, {"sha1(c_enum )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, - {"sha1('1234' )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, - {"sha1(1234 )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 40, types.UnspecifiedLength}, + {"sha1('1234' )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 40, types.UnspecifiedLength}, + {"sha1(1234 )", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 40, types.UnspecifiedLength}, {"sha2(c_int_d , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, {"sha2(c_bigint_d , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, @@ -928,8 +928,8 @@ func (s *testInferTypeSuite) createTestCase4EncryptionFuncs() []typeInferTestCas {"sha2(c_blob_d , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, {"sha2(c_set , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, {"sha2(c_enum , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, - {"sha2('1234' , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, - {"sha2(1234 , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, + {"sha2('1234' , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 128, types.UnspecifiedLength}, + {"sha2(1234 , 0)", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 128, types.UnspecifiedLength}, {"sha2(c_int_d , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, {"sha2(c_bigint_d , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, @@ -947,19 +947,19 @@ func (s *testInferTypeSuite) createTestCase4EncryptionFuncs() []typeInferTestCas {"sha2(c_blob_d , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, {"sha2(c_set , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, {"sha2(c_enum , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, - {"sha2('1234' , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, - {"sha2(1234 , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 128, types.UnspecifiedLength}, + {"sha2('1234' , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 128, types.UnspecifiedLength}, + {"sha2(1234 , '256')", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 128, types.UnspecifiedLength}, {"AES_ENCRYPT(c_int_d, 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, {"AES_ENCRYPT(c_char, 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, {"AES_ENCRYPT(c_varchar, 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, {"AES_ENCRYPT(c_binary, 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, {"AES_ENCRYPT(c_varbinary, 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, - {"AES_ENCRYPT('', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 16, types.UnspecifiedLength}, - {"AES_ENCRYPT('111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 16, types.UnspecifiedLength}, - {"AES_ENCRYPT('111111111111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 16, types.UnspecifiedLength}, - {"AES_ENCRYPT('1111111111111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, - {"AES_ENCRYPT('11111111111111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, + {"AES_ENCRYPT('', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 16, types.UnspecifiedLength}, + {"AES_ENCRYPT('111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 16, types.UnspecifiedLength}, + {"AES_ENCRYPT('111111111111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 16, types.UnspecifiedLength}, + {"AES_ENCRYPT('1111111111111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 32, types.UnspecifiedLength}, + {"AES_ENCRYPT('11111111111111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 32, types.UnspecifiedLength}, {"AES_DECRYPT('1111111111111111', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 16, types.UnspecifiedLength}, {"AES_DECRYPT('11111111111111112222222222222222', 'key')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 32, types.UnspecifiedLength}, @@ -970,8 +970,8 @@ func (s *testInferTypeSuite) createTestCase4EncryptionFuncs() []typeInferTestCas {"COMPRESS(c_varchar)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 33, types.UnspecifiedLength}, {"COMPRESS(c_binary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 33, types.UnspecifiedLength}, {"COMPRESS(c_varbinary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 33, types.UnspecifiedLength}, - {"COMPRESS('')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 13, types.UnspecifiedLength}, - {"COMPRESS('abcde')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 18, types.UnspecifiedLength}, + {"COMPRESS('')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 13, types.UnspecifiedLength}, + {"COMPRESS('abcde')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 18, types.UnspecifiedLength}, {"UNCOMPRESS(c_int_d)", mysql.TypeLongBlob, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxBlobWidth, types.UnspecifiedLength}, {"UNCOMPRESS(c_char)", mysql.TypeLongBlob, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxBlobWidth, types.UnspecifiedLength}, @@ -980,8 +980,8 @@ func (s *testInferTypeSuite) createTestCase4EncryptionFuncs() []typeInferTestCas {"UNCOMPRESSED_LENGTH(c_varchar)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, {"UNCOMPRESSED_LENGTH(c_int_d)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, - {"RANDOM_BYTES(5)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 1024, types.UnspecifiedLength}, - {"RANDOM_BYTES('123')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 1024, types.UnspecifiedLength}, + {"RANDOM_BYTES(5)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1024, types.UnspecifiedLength}, + {"RANDOM_BYTES('123')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1024, types.UnspecifiedLength}, {"RANDOM_BYTES('abc')", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag, 1024, types.UnspecifiedLength}, } } @@ -1143,8 +1143,8 @@ func (s *testInferTypeSuite) createTestCase4OpFuncs() []typeInferTestCase { {"c_time_d is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, {"c_enum is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, {"c_text_d is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, - {"18446 is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, - {"1844674.1 is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, + {"18446 is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1, 0}, + {"1844674.1 is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1, 0}, {"c_int_d is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, {"c_decimal is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, @@ -1154,8 +1154,8 @@ func (s *testInferTypeSuite) createTestCase4OpFuncs() []typeInferTestCase { {"c_time_d is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, {"c_enum is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, {"c_text_d is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, - {"18446 is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, - {"1844674.1 is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, + {"18446 is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1, 0}, + {"1844674.1 is false", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 1, 0}, } } @@ -1193,14 +1193,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, 44, types.UnspecifiedLength}, - {`time_format(123456, '%r%r%r%r')`, mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 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, 44, types.UnspecifiedLength}, - {`date_format(151113102019.12, '%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, 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}, @@ -1234,8 +1234,8 @@ func (s *testInferTypeSuite) createTestCase4TimeFuncs() []typeInferTestCase { {"unix_timestamp(c_set )", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 18, 6}, {"unix_timestamp(c_enum )", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 18, 6}, {"unix_timestamp(null )", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 11, 0}, - {"unix_timestamp('12:12:12.123')", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 15, 3}, - {"unix_timestamp('12:12:12.1234')", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag, 16, 4}, + {"unix_timestamp('12:12:12.123')", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 15, 3}, + {"unix_timestamp('12:12:12.1234')", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 16, 4}, // TODO: Add string literal tests for UNIX_TIMESTAMP. UNIX_TIMESTAMP respects the fsp in string literals. {"timestampdiff(MONTH, c_datetime, c_datetime)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 20, 0}, @@ -1664,39 +1664,39 @@ func (s *testInferTypeSuite) createTestCase4TimeFuncs() []typeInferTestCase { {"dayName(c_set )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 10, types.UnspecifiedLength}, {"dayName(c_enum )", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 10, types.UnspecifiedLength}, - {"now() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 19, 0}, - {"now(0) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 19, 0}, - {"now(1) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 21, 1}, - {"now(2) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 22, 2}, - {"now(3) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 23, 3}, - {"now(4) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 24, 4}, - {"now(5) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 25, 5}, - {"now(6) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 26, 6}, + {"now() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 19, 0}, + {"now(0) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 19, 0}, + {"now(1) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 21, 1}, + {"now(2) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 22, 2}, + {"now(3) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 23, 3}, + {"now(4) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 24, 4}, + {"now(5) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 25, 5}, + {"now(6) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 26, 6}, {"now(7) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 26, 6}, - {"utc_timestamp() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 19, 0}, - {"utc_timestamp(0) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 19, 0}, - {"utc_timestamp(1) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 21, 1}, - {"utc_timestamp(2) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 22, 2}, - {"utc_timestamp(3) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 23, 3}, - {"utc_timestamp(4) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 24, 4}, - {"utc_timestamp(5) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 25, 5}, - {"utc_timestamp(6) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 26, 6}, + {"utc_timestamp() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 19, 0}, + {"utc_timestamp(0) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 19, 0}, + {"utc_timestamp(1) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 21, 1}, + {"utc_timestamp(2) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 22, 2}, + {"utc_timestamp(3) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 23, 3}, + {"utc_timestamp(4) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 24, 4}, + {"utc_timestamp(5) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 25, 5}, + {"utc_timestamp(6) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 26, 6}, {"utc_timestamp(7) ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 26, 6}, - {"utc_time() ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 8, 0}, - {"utc_time(0) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 8, 0}, - {"utc_time(1) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 10, 1}, - {"utc_time(2) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 11, 2}, - {"utc_time(3) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 12, 3}, - {"utc_time(4) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 13, 4}, - {"utc_time(5) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 14, 5}, - {"utc_time(6) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 6}, + {"utc_time() ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 8, 0}, + {"utc_time(0) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 8, 0}, + {"utc_time(1) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 1}, + {"utc_time(2) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 11, 2}, + {"utc_time(3) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 12, 3}, + {"utc_time(4) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 13, 4}, + {"utc_time(5) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 14, 5}, + {"utc_time(6) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 15, 6}, {"utc_time(7) ", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 6}, - {"utc_date() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, - {"curdate()", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, - {"sysdate(4)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 19, 0}, + {"utc_date() ", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"curdate()", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"sysdate(4)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 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}, @@ -1766,9 +1766,9 @@ func (s *testInferTypeSuite) createTestCase4TimeFuncs() []typeInferTestCase { {"quarter(c_set )", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, {"quarter(c_enum )", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 1, 0}, - {"current_time()", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDurationWidthNoFsp, int(types.MinFsp)}, - {"current_time(0)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDurationWidthWithFsp, int(types.MinFsp)}, - {"current_time(6)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDurationWidthWithFsp, int(types.MaxFsp)}, + {"current_time()", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxDurationWidthNoFsp, int(types.MinFsp)}, + {"current_time(0)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxDurationWidthWithFsp, int(types.MinFsp)}, + {"current_time(6)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxDurationWidthWithFsp, int(types.MaxFsp)}, {"sec_to_time(c_int_d )", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, {"sec_to_time(c_bigint_d )", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, @@ -1857,14 +1857,14 @@ func (s *testInferTypeSuite) createTestCase4TimeFuncs() []typeInferTestCase { {"maketime(c_int_d, c_int_d, c_varchar)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 17, 6}, {"maketime(c_int_d, c_int_d, 1.2345)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 4}, - {"get_format(DATE, 'USA')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 17, types.UnspecifiedLength}, + {"get_format(DATE, 'USA')", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 17, types.UnspecifiedLength}, {"convert_tz(c_time_d, c_text_d, c_text_d)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDatetimeWidthWithFsp, int(types.MaxFsp)}, - {"from_unixtime(20170101.999)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDatetimeWidthWithFsp, 3}, - {"from_unixtime(20170101.1234567)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDatetimeWidthWithFsp, int(types.MaxFsp)}, - {"from_unixtime('20170101.999')", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDatetimeWidthWithFsp, int(types.MaxFsp)}, - {"from_unixtime(20170101.123, '%H')", mysql.TypeVarString, charset.CharsetUTF8MB4, 0, 2, types.UnspecifiedLength}, + {"from_unixtime(20170101.999)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxDatetimeWidthWithFsp, 3}, + {"from_unixtime(20170101.1234567)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxDatetimeWidthWithFsp, int(types.MaxFsp)}, + {"from_unixtime('20170101.999')", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxDatetimeWidthWithFsp, int(types.MaxFsp)}, + {"from_unixtime(20170101.123, '%H')", mysql.TypeVarString, charset.CharsetUTF8MB4, mysql.NotNullFlag, 2, types.UnspecifiedLength}, {"extract(day from c_char)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0}, {"extract(hour from c_char)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxIntWidth, 0}, @@ -1911,13 +1911,13 @@ func (s *testInferTypeSuite) createTestCase4LikeFuncs() []typeInferTestCase { func (s *testInferTypeSuite) createTestCase4Literals() []typeInferTestCase { return []typeInferTestCase{ - {"time '00:00:00'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, - {"time '00'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, - {"time '3 00:00:00'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, - {"time '3 00:00:00.1234'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 4}, - {"timestamp '2017-01-01 01:01:01'", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, mysql.MaxDatetimeWidthNoFsp, 0}, - {"timestamp '2017-01-00000000001 01:01:01.001'", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 23, 3}, - {"date '2017-01-01'", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, + {"time '00:00:00'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"time '00'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"time '3 00:00:00'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, + {"time '3 00:00:00.1234'", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 15, 4}, + {"timestamp '2017-01-01 01:01:01'", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, mysql.MaxDatetimeWidthNoFsp, 0}, + {"timestamp '2017-01-00000000001 01:01:01.001'", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 23, 3}, + {"date '2017-01-01'", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag | mysql.NotNullFlag, 10, 0}, } } diff --git a/planner/core/physical_plans.go b/planner/core/physical_plans.go index 150f56a06bedf..2ca952025ba0d 100644 --- a/planner/core/physical_plans.go +++ b/planner/core/physical_plans.go @@ -773,7 +773,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 677dc702eec13..567392f02e241 100644 --- a/server/column.go +++ b/server/column.go @@ -75,9 +75,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 4f6ca53fd9083..c78f7847c9236 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -908,15 +908,27 @@ 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) + } } diff --git a/types/field_type.go b/types/field_type.go index a097a59130747..ca4f66b41369d 100644 --- a/types/field_type.go +++ b/types/field_type.go @@ -169,6 +169,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 8381398935d6e..7fa1864e349b0 100644 --- a/types/field_type_test.go +++ b/types/field_type_test.go @@ -170,31 +170,31 @@ 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 { var ft FieldType From c15054be291e7efdc3814ba63483bbe8aa4ff5d0 Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Tue, 1 Dec 2020 14:57:15 +0800 Subject: [PATCH 2/9] fixup --- cmd/explaintest/r/explain.result | 2 +- cmd/explaintest/r/explain_easy.result | 29 ++++++++++++++------------- server/tidb_test.go | 14 +++++++++++++ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/cmd/explaintest/r/explain.result b/cmd/explaintest/r/explain.result index cd87312a0d2dd..83f6965ff8536 100644 --- a/cmd/explaintest/r/explain.result +++ b/cmd/explaintest/r/explain.result @@ -43,4 +43,4 @@ drop view if exists v; create view v as select cast(replace(substring_index(substring_index("",',',1),':',-1),'"','') as CHAR(32)) as event_id; desc v; Field Type Null Key Default Extra -event_id varchar(32) YES NULL +event_id varchar(32) NO NULL diff --git a/cmd/explaintest/r/explain_easy.result b/cmd/explaintest/r/explain_easy.result index c0a846b044f5d..b6890df1c86cf 100644 --- a/cmd/explaintest/r/explain_easy.result +++ b/cmd/explaintest/r/explain_easy.result @@ -613,20 +613,21 @@ HashJoin_7 8002.00 root right outer join, equal:[eq(test.t.nb, test.t.nb)] └─TableFullScan_12 10000.00 cop[tikv] table:tb keep order:false, stats:pseudo explain select ifnull(t.a, 1) in (select count(*) from t s , t t1 where s.a = t.a and s.a = t1.a) from t; id estRows task access object operator info -Projection_12 10000.00 root Column#14 -└─Apply_14 10000.00 root CARTESIAN left outer semi join, other cond:eq(ifnull(test.t.a, 1), Column#13) - ├─TableReader_16(Build) 10000.00 root data:TableFullScan_15 - │ └─TableFullScan_15 10000.00 cop[tikv] table:t keep order:false, stats:pseudo - └─HashAgg_19(Probe) 1.00 root funcs:count(Column#15)->Column#13 - └─HashJoin_20 9.99 root inner join, equal:[eq(test.t.a, test.t.a)] - ├─HashAgg_30(Build) 7.99 root group by:test.t.a, funcs:count(Column#16)->Column#15, funcs:firstrow(test.t.a)->test.t.a - │ └─TableReader_31 7.99 root data:HashAgg_25 - │ └─HashAgg_25 7.99 cop[tikv] group by:test.t.a, funcs:count(1)->Column#16 - │ └─Selection_29 9.99 cop[tikv] eq(test.t.a, test.t.a), not(isnull(test.t.a)) - │ └─TableFullScan_28 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo - └─TableReader_24(Probe) 9.99 root data:Selection_23 - └─Selection_23 9.99 cop[tikv] eq(test.t.a, test.t.a), not(isnull(test.t.a)) - └─TableFullScan_22 10000.00 cop[tikv] table:s keep order:false, stats:pseudo +Projection_13 10000.00 root Column#14 +└─Apply_15 10000.00 root left outer semi join, equal:[eq(Column#15, Column#13)] + ├─Projection_16(Build) 10000.00 root test.t.a, ifnull(test.t.a, 1)->Column#15 + │ └─TableReader_18 10000.00 root data:TableFullScan_17 + │ └─TableFullScan_17 10000.00 cop[tikv] table:t keep order:false, stats:pseudo + └─HashAgg_21(Probe) 1.00 root funcs:count(Column#17)->Column#13 + └─HashJoin_22 9.99 root inner join, equal:[eq(test.t.a, test.t.a)] + ├─HashAgg_32(Build) 7.99 root group by:test.t.a, funcs:count(Column#18)->Column#17, funcs:firstrow(test.t.a)->test.t.a + │ └─TableReader_33 7.99 root data:HashAgg_27 + │ └─HashAgg_27 7.99 cop[tikv] group by:test.t.a, funcs:count(1)->Column#18 + │ └─Selection_31 9.99 cop[tikv] eq(test.t.a, test.t.a), not(isnull(test.t.a)) + │ └─TableFullScan_30 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo + └─TableReader_26(Probe) 9.99 root data:Selection_25 + └─Selection_25 9.99 cop[tikv] eq(test.t.a, test.t.a), not(isnull(test.t.a)) + └─TableFullScan_24 10000.00 cop[tikv] table:s keep order:false, stats:pseudo drop table if exists t; create table t(a int); explain select * from t where _tidb_rowid = 0; diff --git a/server/tidb_test.go b/server/tidb_test.go index eb4a6d3b0d0fe..64c7330ef2a2f 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -952,6 +952,20 @@ func (ts *tidbTestSuite) TestNullFlag(c *C) { 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) + } } func (ts *tidbTestSuite) TestGracefulShutdown(c *C) { From c0586d867235aeecf37f2f5c995c80eb3c76f888 Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Tue, 1 Dec 2020 15:15:20 +0800 Subject: [PATCH 3/9] fixup --- expression/constant.go | 2 +- types/field_type.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/expression/constant.go b/expression/constant.go index c6e980d52e4c5..83b60658c02fa 100644 --- a/expression/constant.go +++ b/expression/constant.go @@ -125,7 +125,7 @@ func (c *Constant) GetType() *types.FieldType { types.DefaultParamTypeForValue(dt.GetValue(), tp) return tp } - if !c.Value.IsNull() { + if !c.Value.IsNull() && c.RetType.Flag&mysql.NotNullFlag == 0 { c.once.Do(func() { c.RetType = c.RetType.Clone() c.RetType.Flag |= mysql.NotNullFlag diff --git a/types/field_type.go b/types/field_type.go index 2f3de13215c1b..1c6098816ff68 100644 --- a/types/field_type.go +++ b/types/field_type.go @@ -193,9 +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 - } + // if value != nil { + // tp.Flag |= mysql.NotNullFlag + // } switch x := value.(type) { case nil: tp.Tp = mysql.TypeNull From ad13f928280591ef6f60a6d3fd29852d90e72d4a Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Tue, 1 Dec 2020 15:32:31 +0800 Subject: [PATCH 4/9] fixup --- types/field_type.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/types/field_type.go b/types/field_type.go index 1c6098816ff68..2f3de13215c1b 100644 --- a/types/field_type.go +++ b/types/field_type.go @@ -193,9 +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 - // } + if value != nil { + tp.Flag |= mysql.NotNullFlag + } switch x := value.(type) { case nil: tp.Tp = mysql.TypeNull From bd712738779fb096b99ca8529cbbfa2a3c527812 Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Tue, 1 Dec 2020 18:51:08 +0800 Subject: [PATCH 5/9] test --- expression/builtin_control.go | 6 ++++++ expression/constant.go | 24 +++++++++++++++++------- types/field_type.go | 13 ++++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/expression/builtin_control.go b/expression/builtin_control.go index a0b4eaa53e52f..b603401ad871e 100644 --- a/expression/builtin_control.go +++ b/expression/builtin_control.go @@ -193,6 +193,12 @@ func (c *caseWhenFunctionClass) getFunction(ctx sessionctx.Context, args []Expre fieldTp.Flen, fieldTp.Decimal = 0, types.UnspecifiedLength types.SetBinChsClnFlag(fieldTp) } + // it's hard to distinguish not null flag, because + // 1. the args[0] may be null + // 2. no ELSE part + // and MySQL 8.0 also does not provide any not null flag in CASE WHEN + fieldTp.Flag &^= mysql.NotNullFlag + argTps := make([]types.EvalType, 0, l) for i := 0; i < l-1; i += 2 { if args[i], err = wrapWithIsTrue(ctx, true, args[i], false); err != nil { diff --git a/expression/constant.go b/expression/constant.go index 83b60658c02fa..aa81d8c8d0c68 100644 --- a/expression/constant.go +++ b/expression/constant.go @@ -59,7 +59,7 @@ func NewNull() *Constant { type Constant struct { Value types.Datum // once protects the changes of RetType - once sync.Once + lock sync.Mutex RetType *types.FieldType // DeferredExpr holds deferred function in PlanCache cached plan. // it's only used to represent non-deterministic functions(see expression.DeferredFunctions) @@ -77,7 +77,6 @@ type Constant struct { func (c *Constant) Clone() Expression { con := &Constant{ Value: c.Value, - once: sync.Once{}, RetType: c.RetType, DeferredExpr: c.DeferredExpr, ParamMarker: c.ParamMarker, @@ -125,11 +124,22 @@ func (c *Constant) GetType() *types.FieldType { types.DefaultParamTypeForValue(dt.GetValue(), tp) return tp } - if !c.Value.IsNull() && c.RetType.Flag&mysql.NotNullFlag == 0 { - c.once.Do(func() { - c.RetType = c.RetType.Clone() - c.RetType.Flag |= mysql.NotNullFlag - }) + if !c.Value.IsNull() { + // c.once.Do(func() { + // c.RetType = c.RetType.Clone() + // c.RetType.Flag |= mysql.NotNullFlag + // }) + // tp := c.RetType.Clone() + // tp.Flag |= mysql.NotNullFlag + // return tp + + c.lock.Lock() + c.RetType.Flag |= mysql.NotNullFlag + c.lock.Unlock() + } else { + c.lock.Lock() + c.RetType.Flag &^= mysql.NotNullFlag + c.lock.Unlock() } return c.RetType } diff --git a/types/field_type.go b/types/field_type.go index 2f3de13215c1b..63a12d3454e12 100644 --- a/types/field_type.go +++ b/types/field_type.go @@ -66,8 +66,12 @@ func NewFieldTypeWithCollation(tp byte, collation string, length int) *FieldType // Aggregation is performed by MergeFieldType function. func AggFieldType(tps []*FieldType) *FieldType { var currType FieldType + notNull := true isMixedSign := false for i, t := range tps { + if t.Flag&mysql.NotNullFlag == 0 { + notNull = false + } if i == 0 && currType.Tp == mysql.TypeUnspecified { currType = *t continue @@ -98,6 +102,9 @@ func AggFieldType(tps []*FieldType) *FieldType { } } } + if !notNull { + currType.Flag &^= mysql.NotNullFlag + } return &currType } @@ -193,9 +200,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 - } + // if value != nil { + // tp.Flag |= mysql.NotNullFlag + // } switch x := value.(type) { case nil: tp.Tp = mysql.TypeNull From 68a7d6b49a8284edf3cd6d94055b37e00ccd39af Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Tue, 1 Dec 2020 19:08:44 +0800 Subject: [PATCH 6/9] test --- expression/integration_test.go | 13 +++++++++++++ server/tidb_test.go | 17 +++++++++++++++++ types/field_type.go | 13 +++---------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/expression/integration_test.go b/expression/integration_test.go index 67208b554ae8a..56265eacb4bca 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -2879,6 +2879,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")) // test warnings tk.MustQuery("select case when b=0 then 1 else 1/b end from t") tk.MustQuery("show warnings").Check(testkit.Rows()) diff --git a/server/tidb_test.go b/server/tidb_test.go index 64c7330ef2a2f..c36b6fa7ede23 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -966,6 +966,23 @@ func (ts *tidbTestSuite) TestNullFlag(c *C) { 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) + } } func (ts *tidbTestSuite) TestGracefulShutdown(c *C) { diff --git a/types/field_type.go b/types/field_type.go index 63a12d3454e12..2f3de13215c1b 100644 --- a/types/field_type.go +++ b/types/field_type.go @@ -66,12 +66,8 @@ func NewFieldTypeWithCollation(tp byte, collation string, length int) *FieldType // Aggregation is performed by MergeFieldType function. func AggFieldType(tps []*FieldType) *FieldType { var currType FieldType - notNull := true isMixedSign := false for i, t := range tps { - if t.Flag&mysql.NotNullFlag == 0 { - notNull = false - } if i == 0 && currType.Tp == mysql.TypeUnspecified { currType = *t continue @@ -102,9 +98,6 @@ func AggFieldType(tps []*FieldType) *FieldType { } } } - if !notNull { - currType.Flag &^= mysql.NotNullFlag - } return &currType } @@ -200,9 +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 - // } + if value != nil { + tp.Flag |= mysql.NotNullFlag + } switch x := value.(type) { case nil: tp.Tp = mysql.TypeNull From 9000dc9d891e083e486b53f9665e5cd1587643bb Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Fri, 4 Dec 2020 11:24:35 +0800 Subject: [PATCH 7/9] fix --- expression/simple_rewriter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/simple_rewriter.go b/expression/simple_rewriter.go index 37a1a5c940f07..2fd6ab148c07a 100644 --- a/expression/simple_rewriter.go +++ b/expression/simple_rewriter.go @@ -57,7 +57,7 @@ func ParseSimpleExprCastWithTableInfo(ctx sessionctx.Context, exprStr string, ta if err != nil { return nil, err } - e = BuildCastFunction(ctx, e, targetFt) + e = BuildCastFunction(ctx, e, targetFt.Clone()) return e, nil } From da21486564bfd4759f26b9243c151719a7c53f78 Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Tue, 8 Dec 2020 11:52:36 +0800 Subject: [PATCH 8/9] save --- tests/globalkilltest/go.sum | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/globalkilltest/go.sum b/tests/globalkilltest/go.sum index e6365673c2875..f8902b2fecae0 100644 --- a/tests/globalkilltest/go.sum +++ b/tests/globalkilltest/go.sum @@ -411,6 +411,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/failpoint v0.0.0-20191029060244-12f4ac2fd11d/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce h1:Y1kCxlCtlPTMtVcOkjUcuQKh+YrluSo7+7YMCQSzy30= From 616018514b211adaae750fe8a6edc1341be0b6c8 Mon Sep 17 00:00:00 2001 From: Feng Liyuan Date: Tue, 8 Dec 2020 19:10:34 +0800 Subject: [PATCH 9/9] add SELECT NULL case --- server/tidb_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/tidb_test.go b/server/tidb_test.go index d3f0209a5e948..da3a486eb9f90 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -983,6 +983,14 @@ func (ts *tidbTestSuite) TestNullFlag(c *C) { 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) {