From 262ebd5f07bccde889c0d427558755416010ed35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Mon, 6 Feb 2023 18:31:58 +0100 Subject: [PATCH] server: Implement column defaults for `mysql.ComFieldList` (#40765) close pingcap/tidb#40764 --- server/column.go | 45 ++++++++++++++-------- server/column_test.go | 77 +++++++++++++++++++++++++------------- server/conn.go | 8 +--- server/conn_test.go | 9 ++--- server/driver_tidb.go | 15 ++++---- server/driver_tidb_test.go | 23 ++++++------ 6 files changed, 105 insertions(+), 72 deletions(-) diff --git a/server/column.go b/server/column.go index 2ef6323d83b5f..155a1b0e897a1 100644 --- a/server/column.go +++ b/server/column.go @@ -15,6 +15,8 @@ package server import ( + "fmt" + "github.com/pingcap/tidb/parser/charset" "github.com/pingcap/tidb/parser/mysql" ) @@ -23,22 +25,30 @@ const maxColumnNameSize = 256 // ColumnInfo contains information of a column type ColumnInfo struct { - Schema string - Table string - OrgTable string - Name string - OrgName string - ColumnLength uint32 - Charset uint16 - Flag uint16 - Decimal uint8 - Type uint8 - DefaultValueLength uint64 - DefaultValue []byte + Schema string + Table string + OrgTable string + Name string + OrgName string + ColumnLength uint32 + Charset uint16 + Flag uint16 + Decimal uint8 + Type uint8 + DefaultValue any } // Dump dumps ColumnInfo to bytes. func (column *ColumnInfo) Dump(buffer []byte, d *resultEncoder) []byte { + return column.dump(buffer, d, false) +} + +// DumpWithDefault dumps ColumnInfo to bytes, including column defaults. This is used for ComFieldList responses. +func (column *ColumnInfo) DumpWithDefault(buffer []byte, d *resultEncoder) []byte { + return column.dump(buffer, d, true) +} + +func (column *ColumnInfo) dump(buffer []byte, d *resultEncoder, withDefault bool) []byte { if d == nil { d = newResultEncoder(charset.CharsetUTF8MB4) } @@ -64,9 +74,14 @@ func (column *ColumnInfo) Dump(buffer []byte, d *resultEncoder) []byte { buffer = append(buffer, column.Decimal) buffer = append(buffer, 0, 0) - if column.DefaultValue != nil { - buffer = dumpUint64(buffer, uint64(len(column.DefaultValue))) - buffer = append(buffer, column.DefaultValue...) + if withDefault { + switch column.DefaultValue { + case "CURRENT_TIMESTAMP", "CURRENT_DATE", nil: + buffer = append(buffer, 251) // NULL + default: + defaultValStr := fmt.Sprintf("%v", column.DefaultValue) + buffer = dumpLengthEncodedString(buffer, []byte(defaultValStr)) + } } return buffer diff --git a/server/column_test.go b/server/column_test.go index 9d54a643f7f7b..e2251040e1f9a 100644 --- a/server/column_test.go +++ b/server/column_test.go @@ -23,21 +23,47 @@ import ( func TestDumpColumn(t *testing.T) { info := ColumnInfo{ - Schema: "testSchema", - Table: "testTable", - OrgTable: "testOrgTable", - Name: "testName", - OrgName: "testOrgName", - ColumnLength: 1, - Charset: 106, - Flag: 0, - Decimal: 1, - Type: 14, - DefaultValueLength: 2, - DefaultValue: []byte{5, 2}, + Schema: "testSchema", + Table: "testTable", + OrgTable: "testOrgTable", + Name: "testName", + OrgName: "testOrgName", + ColumnLength: 1, + Charset: 106, + Flag: 0, + Decimal: 1, + Type: 14, + DefaultValue: []byte{5, 2}, } r := info.Dump(nil, nil) - exp := []byte{0x3, 0x64, 0x65, 0x66, 0xa, 0x74, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x9, 0x74, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0xc, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x8, 0x74, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0xb, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0xc, 0x6a, 0x0, 0x1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x1, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x2} + exp := []byte{0x3, 0x64, 0x65, 0x66, 0xa, 0x74, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x9, 0x74, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0xc, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x8, 0x74, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0xb, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0xc, 0x6a, 0x0, 0x1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x1, 0x0, 0x0} + require.Equal(t, exp, r) + + require.Equal(t, uint16(mysql.SetFlag), dumpFlag(mysql.TypeSet, 0)) + require.Equal(t, uint16(mysql.EnumFlag), dumpFlag(mysql.TypeEnum, 0)) + require.Equal(t, uint16(0), dumpFlag(mysql.TypeString, 0)) + + require.Equal(t, mysql.TypeString, dumpType(mysql.TypeSet)) + require.Equal(t, mysql.TypeString, dumpType(mysql.TypeEnum)) + require.Equal(t, mysql.TypeBit, dumpType(mysql.TypeBit)) +} + +func TestDumpColumnWithDefault(t *testing.T) { + info := ColumnInfo{ + Schema: "testSchema", + Table: "testTable", + OrgTable: "testOrgTable", + Name: "testName", + OrgName: "testOrgName", + ColumnLength: 1, + Charset: 106, + Flag: 0, + Decimal: 1, + Type: 14, + DefaultValue: "test", + } + r := info.DumpWithDefault(nil, nil) + exp := []byte{0x3, 0x64, 0x65, 0x66, 0xa, 0x74, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x9, 0x74, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0xc, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x8, 0x74, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0xb, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0xc, 0x6a, 0x0, 0x1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x1, 0x0, 0x0, 0x4, 0x74, 0x65, 0x73, 0x74} require.Equal(t, exp, r) require.Equal(t, uint16(mysql.SetFlag), dumpFlag(mysql.TypeSet, 0)) @@ -55,20 +81,19 @@ func TestColumnNameLimit(t *testing.T) { aLongName = append(aLongName, 'a') } info := ColumnInfo{ - Schema: "testSchema", - Table: "testTable", - OrgTable: "testOrgTable", - Name: string(aLongName), - OrgName: "testOrgName", - ColumnLength: 1, - Charset: 106, - Flag: 0, - Decimal: 1, - Type: 14, - DefaultValueLength: 2, - DefaultValue: []byte{5, 2}, + Schema: "testSchema", + Table: "testTable", + OrgTable: "testOrgTable", + Name: string(aLongName), + OrgName: "testOrgName", + ColumnLength: 1, + Charset: 106, + Flag: 0, + Decimal: 1, + Type: 14, + DefaultValue: []byte{5, 2}, } r := info.Dump(nil, nil) - exp := []byte{0x3, 0x64, 0x65, 0x66, 0xa, 0x74, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x9, 0x74, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0xc, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0xfc, 0x0, 0x1, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xb, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0xc, 0x6a, 0x0, 0x1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x1, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x2} + exp := []byte{0x3, 0x64, 0x65, 0x66, 0xa, 0x74, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x9, 0x74, 0x65, 0x73, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0xc, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0xfc, 0x0, 0x1, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xb, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0xc, 0x6a, 0x0, 0x1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x1, 0x0, 0x0} require.Equal(t, exp, r) } diff --git a/server/conn.go b/server/conn.go index f5676e1554d24..10d81ffa196b1 100644 --- a/server/conn.go +++ b/server/conn.go @@ -2104,14 +2104,8 @@ func (cc *clientConn) handleFieldList(ctx context.Context, sql string) (err erro cc.initResultEncoder(ctx) defer cc.rsEncoder.clean() for _, column := range columns { - // Current we doesn't output defaultValue but reserve defaultValue length byte to make mariadb client happy. - // https://dev.mysql.com/doc/internals/en/com-query-response.html#column-definition - // TODO: fill the right DefaultValues. - column.DefaultValueLength = 0 - column.DefaultValue = []byte{} - data = data[0:4] - data = column.Dump(data, cc.rsEncoder) + data = column.DumpWithDefault(data, cc.rsEncoder) if err := cc.writePacket(data); err != nil { return err } diff --git a/server/conn_test.go b/server/conn_test.go index fb1cd15102129..6571d7efd5352 100644 --- a/server/conn_test.go +++ b/server/conn_test.go @@ -429,9 +429,9 @@ func TestDispatch(t *testing.T) { in: []byte("t"), err: nil, out: []byte{ - 0x26, 0x0, 0x0, 0xc, 0x3, 0x64, 0x65, 0x66, 0x4, 0x74, 0x65, 0x73, 0x74, 0x1, 0x74, + 0x1f, 0x0, 0x0, 0xc, 0x3, 0x64, 0x65, 0x66, 0x4, 0x74, 0x65, 0x73, 0x74, 0x1, 0x74, 0x1, 0x74, 0x1, 0x61, 0x1, 0x61, 0xc, 0x3f, 0x0, 0xb, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0xd, 0xfe, + 0x0, 0x0, 0x0, 0xfb, 0x1, 0x0, 0x0, 0xd, 0xfe, }, }, { @@ -549,10 +549,9 @@ func TestDispatchClientProtocol41(t *testing.T) { in: []byte("t"), err: nil, out: []byte{ - 0x26, 0x0, 0x0, 0xc, 0x3, 0x64, 0x65, 0x66, 0x4, 0x74, 0x65, 0x73, 0x74, 0x1, 0x74, + 0x1f, 0x0, 0x0, 0xc, 0x3, 0x64, 0x65, 0x66, 0x4, 0x74, 0x65, 0x73, 0x74, 0x1, 0x74, 0x1, 0x74, 0x1, 0x61, 0x1, 0x61, 0xc, 0x3f, 0x0, 0xb, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0xd, 0xfe, - 0x0, 0x0, 0x2, 0x0, + 0x0, 0x0, 0x0, 0xfb, 0x5, 0x0, 0x0, 0x0d, 0xfe, 0x0, 0x0, 0x2, 0x0, }, }, { diff --git a/server/driver_tidb.go b/server/driver_tidb.go index 7b25a998d618b..b37b76a75a889 100644 --- a/server/driver_tidb.go +++ b/server/driver_tidb.go @@ -522,13 +522,14 @@ func unwrapResultSet(rs ResultSet) ResultSet { func convertColumnInfo(fld *ast.ResultField) (ci *ColumnInfo) { ci = &ColumnInfo{ - Name: fld.ColumnAsName.O, - OrgName: fld.Column.Name.O, - Table: fld.TableAsName.O, - Schema: fld.DBName.O, - Flag: uint16(fld.Column.GetFlag()), - Charset: uint16(mysql.CharsetNameToID(fld.Column.GetCharset())), - Type: fld.Column.GetType(), + Name: fld.ColumnAsName.O, + OrgName: fld.Column.Name.O, + Table: fld.TableAsName.O, + Schema: fld.DBName.O, + Flag: uint16(fld.Column.GetFlag()), + Charset: uint16(mysql.CharsetNameToID(fld.Column.GetCharset())), + Type: fld.Column.GetType(), + DefaultValue: fld.Column.GetDefaultValue(), } if fld.Table != nil { diff --git a/server/driver_tidb_test.go b/server/driver_tidb_test.go index b56632937e078..35dd70f438982 100644 --- a/server/driver_tidb_test.go +++ b/server/driver_tidb_test.go @@ -28,18 +28,17 @@ import ( func createColumnByTypeAndLen(tp byte, cl uint32) *ColumnInfo { return &ColumnInfo{ - Schema: "test", - Table: "dual", - OrgTable: "", - Name: "a", - OrgName: "a", - ColumnLength: cl, - Charset: uint16(mysql.CharsetNameToID(charset.CharsetUTF8)), - Flag: uint16(mysql.UnsignedFlag), - Decimal: uint8(0), - Type: tp, - DefaultValueLength: uint64(0), - DefaultValue: nil, + Schema: "test", + Table: "dual", + OrgTable: "", + Name: "a", + OrgName: "a", + ColumnLength: cl, + Charset: uint16(mysql.CharsetNameToID(charset.CharsetUTF8)), + Flag: uint16(mysql.UnsignedFlag), + Decimal: uint8(0), + Type: tp, + DefaultValue: nil, } } func TestConvertColumnInfo(t *testing.T) {