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

infoschema: refine infoschema's MaxLength Precision value #7463

Merged
merged 2 commits into from
Aug 24, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -5410,7 +5410,7 @@ func (b *builtinLastDaySig) evalTime(row chunk.Row) (types.Time, bool, error) {
// getExpressionFsp calculates the fsp from given expression.
func getExpressionFsp(ctx sessionctx.Context, expression Expression) (int, error) {
constExp, isConstant := expression.(*Constant)
if isConstant && types.IsString(expression.GetType()) && !isTemporalColumn(expression) {
if isConstant && types.IsString(expression.GetType().Tp) && !isTemporalColumn(expression) {
str, isNil, err := constExp.EvalString(ctx, chunk.Row{})
if isNil || err != nil {
return 0, errors.Trace(err)
Expand Down
45 changes: 29 additions & 16 deletions infoschema/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -792,8 +792,12 @@ func dataForColumns(ctx sessionctx.Context, schemas []*model.DBInfo) [][]types.D
func dataForColumnsInTable(schema *model.DBInfo, tbl *model.TableInfo) [][]types.Datum {
var rows [][]types.Datum
for i, col := range tbl.Columns {
var charMaxLen, charOctLen, numericPrecision, numericScale, datetimePrecision interface{}
Copy link
Member

Choose a reason for hiding this comment

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

Why not use int instead of interface{}? Are there any benefits of using interface{} here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

using interface{}, we can got NULL result~

Copy link
Member

Choose a reason for hiding this comment

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

interface is really slow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes~~we should void using interface{} as we can, but in this case is special, types.MakeDatums accept args ...interface{} as arguments.

cast to interface always happen, so direct using interface{} local variable is simple.

we also can use *int local varible instead of interface{}, but that will make us step into a well-known trap in go https://play.golang.org/p/qw6UJhvZcrR

colLen, decimal := col.Flen, col.Decimal
defaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimal(col.Tp)
if decimal == types.UnspecifiedLength {
decimal = defaultDecimal
}
if colLen == types.UnspecifiedLength {
colLen = defaultFlen
}
Expand All @@ -808,6 +812,8 @@ func dataForColumnsInTable(schema *model.DBInfo, tbl *model.TableInfo) [][]types
if len(col.Elems) != 0 {
colLen += (len(col.Elems) - 1)
}
charMaxLen = colLen
charOctLen = colLen
} else if col.Tp == mysql.TypeEnum {
// Example: In MySQL enum('a', 'ab', 'cdef') has length 4, because
// the longest string in the enum is 'cdef'
Expand All @@ -818,9 +824,16 @@ func dataForColumnsInTable(schema *model.DBInfo, tbl *model.TableInfo) [][]types
colLen = len(ele)
}
}
}
if decimal == types.UnspecifiedLength {
decimal = defaultDecimal
charMaxLen = colLen
charOctLen = colLen
} else if types.IsString(col.Tp) {
charMaxLen = colLen
charOctLen = colLen
} else if types.IsTypeFractionable(col.Tp) {
datetimePrecision = decimal
} else if types.IsTypeNumeric(col.Tp) {
numericPrecision = colLen
numericScale = decimal
}
columnType := col.FieldType.InfoSchemaStr()
columnDesc := table.NewColDesc(table.ToColumn(col))
Expand All @@ -837,19 +850,19 @@ func dataForColumnsInTable(schema *model.DBInfo, tbl *model.TableInfo) [][]types
columnDefault, // COLUMN_DEFAULT
columnDesc.Null, // IS_NULLABLE
types.TypeToStr(col.Tp, col.Charset), // DATA_TYPE
colLen, // CHARACTER_MAXIMUM_LENGTH
colLen, // CHARACTER_OCTET_LENGTH
decimal, // NUMERIC_PRECISION
0, // NUMERIC_SCALE
0, // DATETIME_PRECISION
col.Charset, // CHARACTER_SET_NAME
col.Collate, // COLLATION_NAME
columnType, // COLUMN_TYPE
columnDesc.Key, // COLUMN_KEY
columnDesc.Extra, // EXTRA
"select,insert,update,references", // PRIVILEGES
columnDesc.Comment, // COLUMN_COMMENT
col.GeneratedExprString, // GENERATION_EXPRESSION
charMaxLen, // CHARACTER_MAXIMUM_LENGTH
charOctLen, // CHARACTER_OCTET_LENGTH
numericPrecision, // NUMERIC_PRECISION
numericScale, // NUMERIC_SCALE
datetimePrecision, // DATETIME_PRECISION
col.Charset, // CHARACTER_SET_NAME
col.Collate, // COLLATION_NAME
columnType, // COLUMN_TYPE
columnDesc.Key, // COLUMN_KEY
columnDesc.Extra, // EXTRA
"select,insert,update,references", // PRIVILEGES
columnDesc.Comment, // COLUMN_COMMENT
col.GeneratedExprString, // GENERATION_EXPRESSION
)
// In mysql, 'character_set_name' and 'collation_name' are setted to null when column type is non-varchar or non-blob in information_schema.
if col.Tp != mysql.TypeVarchar && col.Tp != mysql.TypeBlob {
Expand Down
26 changes: 26 additions & 0 deletions infoschema/tables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@ import (
"github.com/pingcap/tidb/util/testleak"
)

func (s *testSuite) TestInfoschemaFielValue(c *C) {
testleak.BeforeTest()
defer testleak.AfterTest(c)()
store, err := mockstore.NewMockTikvStore()
c.Assert(err, IsNil)
defer store.Close()
session.SetStatsLease(0)
do, err := session.BootstrapSession(store)
c.Assert(err, IsNil)
defer do.Close()

tk := testkit.NewTestKit(c, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists numschema, timeschema")
tk.MustExec("create table numschema(i int(2), f float(4,2), d decimal(4,3))")
tk.MustExec("create table timeschema(d date, dt datetime(3), ts timestamp(3), t time(4), y year(4))")
tk.MustExec("create table strschema(c char(3), c2 varchar(3), b blob(3), t text(3))")

tk.MustQuery("select CHARACTER_MAXIMUM_LENGTH,CHARACTER_OCTET_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE,DATETIME_PRECISION from information_schema.COLUMNS where table_name='numschema'").
Check(testkit.Rows("<nil> <nil> 2 0 <nil>", "<nil> <nil> 4 2 <nil>", "<nil> <nil> 4 3 <nil>")) // FIXME: for mysql first one will be "<nil> <nil> 10 0 <nil>"
tk.MustQuery("select CHARACTER_MAXIMUM_LENGTH,CHARACTER_OCTET_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE,DATETIME_PRECISION from information_schema.COLUMNS where table_name='timeschema'").
Check(testkit.Rows("<nil> <nil> <nil> <nil> <nil>", "<nil> <nil> <nil> <nil> 3", "<nil> <nil> <nil> <nil> 3", "<nil> <nil> <nil> <nil> 4", "<nil> <nil> <nil> <nil> <nil>"))
tk.MustQuery("select CHARACTER_MAXIMUM_LENGTH,CHARACTER_OCTET_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE,DATETIME_PRECISION from information_schema.COLUMNS where table_name='strschema'").
Check(testkit.Rows("3 3 <nil> <nil> <nil>", "3 3 <nil> <nil> <nil>", "3 3 <nil> <nil> <nil>", "3 3 <nil> <nil> <nil>")) // FIXME: for mysql last two will be "255 255 <nil> <nil> <nil>", "255 255 <nil> <nil> <nil>"
}

func (s *testSuite) TestDataForTableRowsCountField(c *C) {
testleak.BeforeTest()
defer testleak.AfterTest(c)()
Expand Down
19 changes: 12 additions & 7 deletions types/etc.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,14 @@ func IsTypeTime(tp byte) bool {
return tp == mysql.TypeDatetime || tp == mysql.TypeDate || tp == mysql.TypeTimestamp
}

// IsTypeFloat returns a boolean indicating whether the tp is floating-point type.
func IsTypeFloat(tp byte) bool {
return tp == mysql.TypeFloat || tp == mysql.TypeDouble
// IsTypeNumeric returns a boolean indicating whether the tp is numeric type.
func IsTypeNumeric(tp byte) bool {
switch tp {
case mysql.TypeBit, mysql.TypeTiny, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeNewDecimal,
mysql.TypeDecimal, mysql.TypeFloat, mysql.TypeDouble, mysql.TypeShort:
return true
}
return false
}

// IsTemporalWithDate returns a boolean indicating
Expand All @@ -87,7 +92,7 @@ func IsTemporalWithDate(tp byte) bool {
// IsBinaryStr returns a boolean indicating
// whether the field type is a binary string type.
func IsBinaryStr(ft *FieldType) bool {
if ft.Collate == charset.CollationBin && IsString(ft) {
if ft.Collate == charset.CollationBin && IsString(ft.Tp) {
return true
}
return false
Expand All @@ -96,16 +101,16 @@ func IsBinaryStr(ft *FieldType) bool {
// IsNonBinaryStr returns a boolean indicating
// whether the field type is a non-binary string type.
func IsNonBinaryStr(ft *FieldType) bool {
if ft.Collate != charset.CollationBin && IsString(ft) {
if ft.Collate != charset.CollationBin && IsString(ft.Tp) {
return true
}
return false
}

// IsString returns a boolean indicating
// whether the field type is a string type.
func IsString(ft *FieldType) bool {
return IsTypeChar(ft.Tp) || IsTypeBlob(ft.Tp) || IsTypeVarchar(ft.Tp) || IsTypeUnspecified(ft.Tp)
func IsString(tp byte) bool {
return IsTypeChar(tp) || IsTypeBlob(tp) || IsTypeVarchar(tp) || IsTypeUnspecified(tp)
}

var type2Str = map[byte]string{
Expand Down