Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: fix some problems related to notNullFlag #27697

Merged
merged 13 commits into from Sep 9, 2021
2 changes: 2 additions & 0 deletions expression/builtin_time.go
Expand Up @@ -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 {
Expand Down
13 changes: 13 additions & 0 deletions expression/integration_test.go
Expand Up @@ -3117,6 +3117,19 @@ func (s *testIntegrationSuite2) TestBuiltin(c *C) {
result.Check(testkit.Rows("<nil> 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("<nil> 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")
Expand Down
41 changes: 22 additions & 19 deletions expression/typeinfer_test.go
Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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},
Expand All @@ -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},
Expand Down Expand Up @@ -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},
Expand All @@ -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},
Expand All @@ -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},
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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},
Expand Down
2 changes: 1 addition & 1 deletion planner/core/physical_plans.go
Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions server/column.go
Expand Up @@ -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)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it's unreasonable.

return flag | uint16(mysql.NotNullFlag)
}
return flag
}
}
Expand Down
65 changes: 58 additions & 7 deletions server/tidb_test.go
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions tests/globalkilltest/go.sum
Expand Up @@ -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=
Expand Down
3 changes: 3 additions & 0 deletions types/field_type.go
Expand Up @@ -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
Expand Down