From db873d68f3c03a6ba59a5b21af59e8d52e7af259 Mon Sep 17 00:00:00 2001 From: lysu Date: Fri, 24 Aug 2018 13:15:21 +0800 Subject: [PATCH] infoschema: set right columns in infoschema by differ type (#7463) --- expression/builtin_time.go | 2 +- infoschema/tables.go | 45 ++++++++++++++++++++++++-------------- infoschema/tables_test.go | 26 ++++++++++++++++++++++ types/etc.go | 19 ++++++++++------ 4 files changed, 68 insertions(+), 24 deletions(-) diff --git a/expression/builtin_time.go b/expression/builtin_time.go index 7d44e77746a80..5b0d76d7cf069 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -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) diff --git a/infoschema/tables.go b/infoschema/tables.go index 324c05e8e919f..f0a88941c76a1 100644 --- a/infoschema/tables.go +++ b/infoschema/tables.go @@ -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{} colLen, decimal := col.Flen, col.Decimal defaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimal(col.Tp) + if decimal == types.UnspecifiedLength { + decimal = defaultDecimal + } if colLen == types.UnspecifiedLength { colLen = defaultFlen } @@ -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' @@ -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)) @@ -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 { diff --git a/infoschema/tables_test.go b/infoschema/tables_test.go index 6db86406e8a53..82f08876f5982 100644 --- a/infoschema/tables_test.go +++ b/infoschema/tables_test.go @@ -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(" 2 0 ", " 4 2 ", " 4 3 ")) // FIXME: for mysql first one will be " 10 0 " + 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(" ", " 3", " 3", " 4", " ")) + 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 ", "3 3 ", "3 3 ", "3 3 ")) // FIXME: for mysql last two will be "255 255 ", "255 255 " +} + func (s *testSuite) TestDataForTableRowsCountField(c *C) { testleak.BeforeTest() defer testleak.AfterTest(c)() diff --git a/types/etc.go b/types/etc.go index efe0cc18d8262..56e551f9735bd 100644 --- a/types/etc.go +++ b/types/etc.go @@ -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 @@ -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 @@ -96,7 +101,7 @@ 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 @@ -104,8 +109,8 @@ func IsNonBinaryStr(ft *FieldType) bool { // 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{