Skip to content

Commit

Permalink
*: restrict the length of enum/set value (pingcap#19109)
Browse files Browse the repository at this point in the history
  • Loading branch information
erwadba authored Nov 4, 2020
1 parent 09c941f commit 6e1aa0d
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 0 deletions.
7 changes: 7 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ type Config struct {
EnableGlobalIndex bool `toml:"enable-global-index" json:"enable-global-index"`
// DeprecateIntegerDisplayWidth indicates whether deprecating the max display length for integer.
DeprecateIntegerDisplayWidth bool `toml:"deprecate-integer-display-length" json:"deprecate-integer-display-length"`
// EnableEnumLengthLimit indicates whether the enum/set element length is limited.
// According to MySQL 8.0 Refman:
// The maximum supported length of an individual SET element is M <= 255 and (M x w) <= 1020,
// where M is the element literal length and w is the number of bytes required for the maximum-length character in the character set.
// See https://dev.mysql.com/doc/refman/8.0/en/string-type-syntax.html for more details.
EnableEnumLengthLimit bool `toml:"enable-enum-length-limit" json:"enable-enum-length-limit"`
}

// UpdateTempStoragePath is to update the `TempStoragePath` if port/statusPort was changed
Expand Down Expand Up @@ -770,6 +776,7 @@ var defaultConf = Config{
SpilledFileEncryptionMethod: SpilledFileEncryptionMethodPlaintext,
},
DeprecateIntegerDisplayWidth: false,
EnableEnumLengthLimit: true,
}

var (
Expand Down
7 changes: 7 additions & 0 deletions config/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ enable-telemetry = true
# a warning like `Integer display width is deprecated and will be removed in a future release`.
deprecate-integer-display-length = false

# enable-enum-length-limit is used to deal with compatibility issues. When true, the enum/set element length is limited.
# According to MySQL 8.0 Refman:
# The maximum supported length of an individual SET element is M <= 255 and (M x w) <= 1020,
# where M is the element literal length and w is the number of bytes required for the maximum-length character in the character set.
# See https://dev.mysql.com/doc/refman/8.0/en/string-type-syntax.html for more details.
enable-enum-length-limit = true

[log]
# Log level: debug, info, warn, error, fatal.
level = "info"
Expand Down
2 changes: 2 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ nested-loop-join-cache-capacity = 100
max-index-length = 3080
skip-register-to-dashboard = true
deprecate-integer-display-length = true
enable-enum-length-limit = false
[performance]
txn-total-size-limit=2000
[tikv-client]
Expand Down Expand Up @@ -271,6 +272,7 @@ spilled-file-encryption-method = "plaintext"
c.Assert(conf.Labels["group"], Equals, "abc")
c.Assert(conf.Security.SpilledFileEncryptionMethod, Equals, SpilledFileEncryptionMethodPlaintext)
c.Assert(conf.DeprecateIntegerDisplayWidth, Equals, true)
c.Assert(conf.EnableEnumLengthLimit, Equals, false)

_, err = f.WriteString(`
[log.file]
Expand Down
12 changes: 12 additions & 0 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -962,8 +962,20 @@ func checkColumnValueConstraint(col *table.Column, collation string) error {
}
valueMap := make(map[string]bool, len(col.Elems))
ctor := collate.GetCollator(collation)
enumLengthLimit := config.GetGlobalConfig().EnableEnumLengthLimit
desc, err := charset.GetCharsetDesc(col.Charset)
if err != nil {
return errors.Trace(err)
}
for i := range col.Elems {
val := string(ctor.Key(col.Elems[i]))
// According to MySQL 8.0 Refman:
// The maximum supported length of an individual ENUM element is M <= 255 and (M x w) <= 1020,
// where M is the element literal length and w is the number of bytes required for the maximum-length character in the character set.
// See https://dev.mysql.com/doc/refman/8.0/en/string-type-syntax.html for more details.
if enumLengthLimit && (len(val) > 255 || len(val)*desc.Maxlen > 1020) {
return ErrTooLongValueForType.GenWithStackByArgs(col.Name)
}
if _, ok := valueMap[val]; ok {
tpStr := "ENUM"
if col.Tp == mysql.TypeSet {
Expand Down
3 changes: 3 additions & 0 deletions ddl/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,7 @@ var (
// ErrWarnDataOutOfRange is returned when the value in a numeric column that is outside the permissible range of the column data type.
// See https://dev.mysql.com/doc/refman/5.5/en/out-of-range-and-overflow.html for details
ErrWarnDataOutOfRange = dbterror.ClassDDL.NewStd(mysql.ErrWarnDataOutOfRange)

// ErrTooLongValueForType is returned when the individual enum element length is too long.
ErrTooLongValueForType = dbterror.ClassDDL.NewStd(mysql.ErrTooLongValueForType)
)
26 changes: 26 additions & 0 deletions ddl/serial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1480,3 +1480,29 @@ func (s *testSerialSuite) TestCreateTableNoBlock(c *C) {
_, err := tk.Exec("create table t(a int)")
c.Assert(err, NotNil)
}

func (s *testSerialSuite) TestCheckEnumLength(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("drop table if exists t1,t2,t3,t4,t5")
tk.MustGetErrCode("create table t1 (a enum('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'))", errno.ErrTooLongValueForType)
tk.MustGetErrCode("create table t1 (a set('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'))", errno.ErrTooLongValueForType)
tk.MustExec("create table t2 (id int primary key)")
tk.MustGetErrCode("alter table t2 add a enum('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')", errno.ErrTooLongValueForType)
tk.MustGetErrCode("alter table t2 add a set('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')", errno.ErrTooLongValueForType)
config.UpdateGlobal(func(conf *config.Config) {
conf.EnableEnumLengthLimit = false
})
_, err := tk.Exec("create table t3 (a enum('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'))")
c.Assert(err, IsNil)
tk.MustExec("insert into t3 values(1)")
tk.MustQuery("select a from t3").Check(testkit.Rows("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
_, err = tk.Exec("create table t4 (a set('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'))")
c.Assert(err, IsNil)

config.UpdateGlobal(func(conf *config.Config) {
conf.EnableEnumLengthLimit = true
})
tk.MustGetErrCode("create table t5 (a enum('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'))", errno.ErrTooLongValueForType)
tk.MustGetErrCode("create table t5 (a set('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'))", errno.ErrTooLongValueForType)
tk.MustExec("drop table if exists t1,t2,t3,t4,t5")
}
1 change: 1 addition & 0 deletions errno/errcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ const (
ErrUserAlreadyExists = 3163
ErrInvalidJSONPathArrayCell = 3165
ErrInvalidEncryptionOption = 3184
ErrTooLongValueForType = 3505
ErrPKIndexCantBeInvisible = 3522
ErrRoleNotGranted = 3530
ErrLockAcquireFailAndNoWaitSet = 3572
Expand Down
1 change: 1 addition & 0 deletions errno/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,7 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{
ErrUserAlreadyExists: mysql.Message("User %s already exists.", nil),
ErrInvalidJSONPathArrayCell: mysql.Message("A path expression is not a path to a cell in an array.", nil),
ErrInvalidEncryptionOption: mysql.Message("Invalid encryption option.", nil),
ErrTooLongValueForType: mysql.Message("Too long enumeration/set value for column %s.", nil),
ErrPKIndexCantBeInvisible: mysql.Message("A primary key index cannot be invisible", nil),
ErrWindowNoSuchWindow: mysql.Message("Window name '%s' is not defined.", nil),
ErrWindowCircularityInWindowGraph: mysql.Message("There is a circularity in the window dependency graph.", nil),
Expand Down
5 changes: 5 additions & 0 deletions errors.toml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ error = '''
Generated column '%s' cannot refer to auto-increment column.
'''

["ddl:3505"]
error = '''
Too long enumeration/set value for column %s.
'''

["ddl:3522"]
error = '''
A primary key index cannot be invisible
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/pingcap/tidb

require (
cloud.google.com/go v0.51.0 // indirect
github.com/BurntSushi/toml v0.3.1
github.com/HdrHistogram/hdrhistogram-go v0.9.0 // indirect
github.com/Jeffail/gabs/v2 v2.5.1
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0 h1:0E3eE8MX426vUOs7aHfI7aN1BrIzzzf4ccKCSfSjGmc=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
Expand Down Expand Up @@ -216,6 +218,7 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200407044318-7d83b28da2e9 h1:K+lX49/3eURCE1IjlaZN//u6c+9nfDAMnyQ9E2dsJbY=
github.com/google/pprof v0.0.0-20200407044318-7d83b28da2e9/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
Expand Down

0 comments on commit 6e1aa0d

Please sign in to comment.