infoschema: refine error code for package infoschema (#13646)

This commit is contained in:
Maxwell
2019-11-26 10:21:43 +08:00
committed by GitHub
parent e2c8c17e92
commit acfc7be794
5 changed files with 105 additions and 116 deletions

View File

@ -646,9 +646,12 @@ func (e *SimpleExec) executeCreateUser(ctx context.Context, s *ast.CreateUserStm
return err1
}
if exists {
user := fmt.Sprintf(`'%s'@'%s'`, spec.User.Username, spec.User.Hostname)
if !s.IfNotExists {
return errors.New("Duplicate user")
return ErrCannotUser.GenWithStackByArgs("CREATE USER", user)
}
err := infoschema.ErrUserAlreadyExists.GenWithStackByArgs(user)
e.ctx.GetSessionVars().StmtCtx.AppendNote(err)
continue
}
pwd, ok := spec.EncodedPassword()
@ -697,10 +700,8 @@ func (e *SimpleExec) executeAlterUser(s *ast.AlterUserStmt) error {
return err
}
if !exists {
failedUsers = append(failedUsers, spec.User.String())
// TODO: Make this error as a warning.
// if s.IfExists {
// }
user := fmt.Sprintf(`'%s'@'%s'`, spec.User.Username, spec.User.Hostname)
failedUsers = append(failedUsers, user)
continue
}
pwd := ""
@ -728,7 +729,13 @@ func (e *SimpleExec) executeAlterUser(s *ast.AlterUserStmt) error {
if err != nil {
return err
}
return ErrCannotUser.GenWithStackByArgs("ALTER USER", strings.Join(failedUsers, ","))
if !s.IfExists {
return ErrCannotUser.GenWithStackByArgs("ALTER USER", strings.Join(failedUsers, ","))
}
for _, user := range failedUsers {
err := infoschema.ErrUserDropExists.GenWithStackByArgs(user)
e.ctx.GetSessionVars().StmtCtx.AppendNote(err)
}
}
domain.GetDomain(e.ctx).NotifyUpdatePrivilege(e.ctx)
return nil

View File

@ -17,6 +17,7 @@ import (
"context"
. "github.com/pingcap/check"
"github.com/pingcap/errors"
"github.com/pingcap/parser/auth"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
@ -254,8 +255,10 @@ func (s *testSuite3) TestUser(c *C) {
// Create duplicate user without IfNotExists will cause error.
createUserSQL = `CREATE USER 'test'@'localhost' IDENTIFIED BY '123';`
_, err := tk.Exec(createUserSQL)
c.Check(err, NotNil)
tk.MustGetErrCode(createUserSQL, mysql.ErrCannotUser)
createUserSQL = `CREATE USER IF NOT EXISTS 'test'@'localhost' IDENTIFIED BY '123';`
tk.MustExec(createUserSQL)
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Note|3163|User 'test'@'localhost' already exists."))
dropUserSQL := `DROP USER IF EXISTS 'test'@'localhost' ;`
tk.MustExec(dropUserSQL)
// Create user test.
@ -274,20 +277,28 @@ func (s *testSuite3) TestUser(c *C) {
tk.MustExec(alterUserSQL)
result = tk.MustQuery(`SELECT Password FROM mysql.User WHERE User="test1" and Host="localhost"`)
result.Check(testkit.Rows(auth.EncodePassword("111")))
alterUserSQL = `ALTER USER 'test_not_exist'@'localhost' IDENTIFIED BY '111';`
tk.MustGetErrCode(alterUserSQL, mysql.ErrCannotUser)
alterUserSQL = `ALTER USER 'test1'@'localhost' IDENTIFIED BY '222', 'test_not_exist'@'localhost' IDENTIFIED BY '111';`
tk.MustGetErrCode(alterUserSQL, mysql.ErrCannotUser)
result = tk.MustQuery(`SELECT Password FROM mysql.User WHERE User="test1" and Host="localhost"`)
result.Check(testkit.Rows(auth.EncodePassword("222")))
alterUserSQL = `ALTER USER IF EXISTS 'test2'@'localhost' IDENTIFIED BY '222', 'test_not_exist'@'localhost' IDENTIFIED BY '1';`
_, err = tk.Exec(alterUserSQL)
c.Check(err, NotNil)
tk.MustExec(alterUserSQL)
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Note|3162|User 'test_not_exist'@'localhost' does not exist."))
result = tk.MustQuery(`SELECT Password FROM mysql.User WHERE User="test2" and Host="localhost"`)
result.Check(testkit.Rows(auth.EncodePassword("222")))
alterUserSQL = `ALTER USER IF EXISTS'test_not_exist'@'localhost' IDENTIFIED BY '1', 'test3'@'localhost' IDENTIFIED BY '333';`
_, err = tk.Exec(alterUserSQL)
c.Check(err, NotNil)
tk.MustExec(alterUserSQL)
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Note|3162|User 'test_not_exist'@'localhost' does not exist."))
result = tk.MustQuery(`SELECT Password FROM mysql.User WHERE User="test3" and Host="localhost"`)
result.Check(testkit.Rows(auth.EncodePassword("333")))
// Test alter user user().
alterUserSQL = `ALTER USER USER() IDENTIFIED BY '1';`
_, err = tk.Exec(alterUserSQL)
c.Check(err, NotNil)
_, err := tk.Exec(alterUserSQL)
c.Check(terror.ErrorEqual(err, errors.New("Session user is empty")), IsTrue, Commentf("err %v", err))
tk.Se, err = session.CreateSession4Test(s.store)
c.Check(err, IsNil)
ctx := tk.Se.(sessionctx.Context)
@ -309,14 +320,11 @@ func (s *testSuite3) TestUser(c *C) {
createUserSQL = `CREATE USER 'test1'@'localhost', 'test3'@'localhost';`
tk.MustExec(createUserSQL)
dropUserSQL = `DROP USER 'test1'@'localhost', 'test2'@'localhost', 'test3'@'localhost';`
_, err = tk.Exec(dropUserSQL)
c.Check(err, NotNil)
tk.MustGetErrCode(dropUserSQL, mysql.ErrCannotUser)
dropUserSQL = `DROP USER 'test3'@'localhost';`
_, err = tk.Exec(dropUserSQL)
c.Check(err, NotNil)
tk.MustGetErrCode(dropUserSQL, mysql.ErrCannotUser)
dropUserSQL = `DROP USER 'test1'@'localhost';`
_, err = tk.Exec(dropUserSQL)
c.Check(err, NotNil)
tk.MustGetErrCode(dropUserSQL, mysql.ErrCannotUser)
// Test positive cases without IF EXISTS.
createUserSQL = `CREATE USER 'test1'@'localhost', 'test3'@'localhost';`
tk.MustExec(createUserSQL)

2
go.mod
View File

@ -38,7 +38,7 @@ require (
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e
github.com/pingcap/kvproto v0.0.0-20191118050206-47672e7eabc0
github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9
github.com/pingcap/parser v0.0.0-20191120083129-cbaf2bd7f17d
github.com/pingcap/parser v0.0.0-20191120165920-d5c49d11cc64
github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0
github.com/pingcap/tidb-tools v3.0.6-0.20191106033616-90632dda3863+incompatible
github.com/pingcap/tipb v0.0.0-20191120020146-6161b015e21e

4
go.sum
View File

@ -183,8 +183,8 @@ github.com/pingcap/kvproto v0.0.0-20191118050206-47672e7eabc0/go.mod h1:WWLmULLO
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw=
github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA=
github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
github.com/pingcap/parser v0.0.0-20191120083129-cbaf2bd7f17d h1:+ev1tNLx9uiVay2b4s9U+vKDWs4z2CCpD41RGJuOZjY=
github.com/pingcap/parser v0.0.0-20191120083129-cbaf2bd7f17d/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v0.0.0-20191120165920-d5c49d11cc64 h1:jpLGhi9hEp6Px9NDKkSjpcWuBdkgSCTxGMlrw9bWipQ=
github.com/pingcap/parser v0.0.0-20191120165920-d5c49d11cc64/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 h1:GIEq+wZfrl2bcJxpuSrEH4H7/nlf5YdmpS+dU9lNIt8=
github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0/go.mod h1:G/6rJpnYwM0LKMec2rI82/5Kg6GaZMvlfB+e6/tvYmI=
github.com/pingcap/tidb-tools v3.0.6-0.20191106033616-90632dda3863+incompatible h1:H1jg0aDWz2SLRh3hNBo2HFtnuHtudIUvBumU7syRkic=

View File

@ -27,50 +27,52 @@ import (
)
var (
// ErrDatabaseDropExists returns for dropping a non-existent database.
ErrDatabaseDropExists = terror.ClassSchema.New(codeDBDropExists, "Can't drop database '%s'; database doesn't exist")
// ErrDatabaseNotExists returns for database not exists.
ErrDatabaseNotExists = terror.ClassSchema.New(codeDatabaseNotExists, "Unknown database '%s'")
// ErrTableNotExists returns for table not exists.
ErrTableNotExists = terror.ClassSchema.New(codeTableNotExists, "Table '%s.%s' doesn't exist")
// ErrColumnNotExists returns for column not exists.
ErrColumnNotExists = terror.ClassSchema.New(codeColumnNotExists, "Unknown column '%s' in '%s'")
// ErrForeignKeyNotMatch returns for foreign key not match.
ErrForeignKeyNotMatch = terror.ClassSchema.New(codeWrongFkDef, "Incorrect foreign key definition for '%s': Key reference and table reference don't match")
// ErrCannotAddForeign returns for foreign key exists.
ErrCannotAddForeign = terror.ClassSchema.New(codeCannotAddForeign, "Cannot add foreign key constraint")
// ErrForeignKeyNotExists returns for foreign key not exists.
ErrForeignKeyNotExists = terror.ClassSchema.New(codeForeignKeyNotExists, "Can't DROP '%s'; check that column/key exists")
// ErrDatabaseExists returns for database already exists.
ErrDatabaseExists = terror.ClassSchema.New(codeDatabaseExists, "Can't create database '%s'; database exists")
// ErrTableExists returns for table already exists.
ErrTableExists = terror.ClassSchema.New(codeTableExists, "Table '%s' already exists")
// ErrTableDropExists returns for dropping a non-existent table.
ErrTableDropExists = terror.ClassSchema.New(codeBadTable, "Unknown table '%s'")
// ErrUserDropExists returns for dropping a non-existent user.
ErrUserDropExists = terror.ClassSchema.New(codeBadUser, "User %s does not exist.")
// ErrColumnExists returns for column already exists.
ErrColumnExists = terror.ClassSchema.New(codeColumnExists, "Duplicate column name '%s'")
// ErrIndexExists returns for index already exists.
ErrIndexExists = terror.ClassSchema.New(codeIndexExists, "Duplicate Index")
// ErrKeyNameDuplicate returns for index duplicate when rename index.
ErrKeyNameDuplicate = terror.ClassSchema.New(codeKeyNameDuplicate, "Duplicate key name '%s'")
// ErrKeyNotExists returns for index not exists.
ErrKeyNotExists = terror.ClassSchema.New(codeKeyNotExists, "Key '%s' doesn't exist in table '%s'")
// ErrMultiplePriKey returns for multiple primary keys.
ErrMultiplePriKey = terror.ClassSchema.New(codeMultiplePriKey, "Multiple primary key defined")
// ErrTooManyKeyParts returns for too many key parts.
ErrTooManyKeyParts = terror.ClassSchema.New(codeTooManyKeyParts, "Too many key parts specified; max %d parts allowed")
// ErrTableNotLockedForWrite returns for write tables when only hold the table read lock.
ErrTableNotLockedForWrite = terror.ClassSchema.New(codeErrTableNotLockedForWrite, mysql.MySQLErrName[mysql.ErrTableNotLockedForWrite])
// ErrTableNotLocked returns when session has explicitly lock tables, then visit unlocked table will return this error.
ErrTableNotLocked = terror.ClassSchema.New(codeErrTableNotLocked, mysql.MySQLErrName[mysql.ErrTableNotLocked])
// ErrNonuniqTable returns when none unique tables errors.
ErrNonuniqTable = terror.ClassSchema.New(codeErrTableNotLocked, mysql.MySQLErrName[mysql.ErrNonuniqTable])
// ErrTableLocked returns when the table was locked by other session.
ErrTableLocked = terror.ClassSchema.New(codeTableLocked, mysql.MySQLErrName[mysql.ErrTableLocked])
ErrDatabaseExists = terror.ClassSchema.New(mysql.ErrDBCreateExists, mysql.MySQLErrName[mysql.ErrDBCreateExists])
// ErrDatabaseDropExists returns for dropping a non-existent database.
ErrDatabaseDropExists = terror.ClassSchema.New(mysql.ErrDBDropExists, mysql.MySQLErrName[mysql.ErrDBDropExists])
// ErrAccessDenied return when the user doesn't have the permission to access the table.
ErrAccessDenied = terror.ClassSchema.New(codeErrAccessDenied, mysql.MySQLErrName[mysql.ErrAccessDenied])
ErrAccessDenied = terror.ClassSchema.New(mysql.ErrAccessDenied, mysql.MySQLErrName[mysql.ErrAccessDenied])
// ErrDatabaseNotExists returns for database not exists.
ErrDatabaseNotExists = terror.ClassSchema.New(mysql.ErrBadDB, mysql.MySQLErrName[mysql.ErrBadDB])
// ErrTableExists returns for table already exists.
ErrTableExists = terror.ClassSchema.New(mysql.ErrTableExists, mysql.MySQLErrName[mysql.ErrTableExists])
// ErrTableDropExists returns for dropping a non-existent table.
ErrTableDropExists = terror.ClassSchema.New(mysql.ErrBadTable, mysql.MySQLErrName[mysql.ErrBadTable])
// ErrColumnNotExists returns for column not exists.
ErrColumnNotExists = terror.ClassSchema.New(mysql.ErrBadField, mysql.MySQLErrName[mysql.ErrBadField])
// ErrColumnExists returns for column already exists.
ErrColumnExists = terror.ClassSchema.New(mysql.ErrDupFieldName, mysql.MySQLErrName[mysql.ErrDupFieldName])
// ErrKeyNameDuplicate returns for index duplicate when rename index.
ErrKeyNameDuplicate = terror.ClassSchema.New(mysql.ErrDupKeyName, mysql.MySQLErrName[mysql.ErrDupKeyName])
// ErrNonuniqTable returns when none unique tables errors.
ErrNonuniqTable = terror.ClassSchema.New(mysql.ErrNonuniqTable, mysql.MySQLErrName[mysql.ErrNonuniqTable])
// ErrMultiplePriKey returns for multiple primary keys.
ErrMultiplePriKey = terror.ClassSchema.New(mysql.ErrMultiplePriKey, mysql.MySQLErrName[mysql.ErrMultiplePriKey])
// ErrTooManyKeyParts returns for too many key parts.
ErrTooManyKeyParts = terror.ClassSchema.New(mysql.ErrTooManyKeyParts, mysql.MySQLErrName[mysql.ErrTooManyKeyParts])
// ErrForeignKeyNotExists returns for foreign key not exists.
ErrForeignKeyNotExists = terror.ClassSchema.New(mysql.ErrCantDropFieldOrKey, mysql.MySQLErrName[mysql.ErrCantDropFieldOrKey])
// ErrTableNotLockedForWrite returns for write tables when only hold the table read lock.
ErrTableNotLockedForWrite = terror.ClassSchema.New(mysql.ErrTableNotLockedForWrite, mysql.MySQLErrName[mysql.ErrTableNotLockedForWrite])
// ErrTableNotLocked returns when session has explicitly lock tables, then visit unlocked table will return this error.
ErrTableNotLocked = terror.ClassSchema.New(mysql.ErrTableNotLocked, mysql.MySQLErrName[mysql.ErrTableNotLocked])
// ErrTableNotExists returns for table not exists.
ErrTableNotExists = terror.ClassSchema.New(mysql.ErrNoSuchTable, mysql.MySQLErrName[mysql.ErrNoSuchTable])
// ErrKeyNotExists returns for index not exists.
ErrKeyNotExists = terror.ClassSchema.New(mysql.ErrKeyDoesNotExist, mysql.MySQLErrName[mysql.ErrKeyDoesNotExist])
// ErrCannotAddForeign returns for foreign key exists.
ErrCannotAddForeign = terror.ClassSchema.New(mysql.ErrCannotAddForeign, mysql.MySQLErrName[mysql.ErrCannotAddForeign])
// ErrForeignKeyNotMatch returns for foreign key not match.
ErrForeignKeyNotMatch = terror.ClassSchema.New(mysql.ErrWrongFkDef, mysql.MySQLErrName[mysql.ErrWrongFkDef])
// ErrIndexExists returns for index already exists.
ErrIndexExists = terror.ClassSchema.New(mysql.ErrDupIndex, mysql.MySQLErrName[mysql.ErrDupIndex])
// ErrUserDropExists returns for dropping a non-existent user.
ErrUserDropExists = terror.ClassSchema.New(mysql.ErrBadUser, mysql.MySQLErrName[mysql.ErrBadUser])
// ErrUserAlreadyExists return for creating a existent user.
ErrUserAlreadyExists = terror.ClassSchema.New(mysql.ErrUserAlreadyExists, mysql.MySQLErrName[mysql.ErrUserAlreadyExists])
// ErrTableLocked returns when the table was locked by other session.
ErrTableLocked = terror.ClassSchema.New(mysql.ErrTableLocked, mysql.MySQLErrName[mysql.ErrTableLocked])
)
// InfoSchema is the interface used to retrieve the schema information.
@ -317,59 +319,31 @@ func (h *Handle) EmptyClone() *Handle {
return newHandle
}
// Schema error codes.
const (
codeDBDropExists terror.ErrCode = 1008
codeDatabaseNotExists = 1049
codeTableNotExists = 1146
codeColumnNotExists = 1054
codeCannotAddForeign = 1215
codeForeignKeyNotExists = 1091
codeWrongFkDef = 1239
codeDatabaseExists = 1007
codeTableExists = 1050
codeBadTable = 1051
codeBadUser = 3162
codeColumnExists = 1060
codeIndexExists = 1831
codeMultiplePriKey = 1068
codeTooManyKeyParts = 1070
codeKeyNameDuplicate = 1061
codeKeyNotExists = 1176
codeErrTableNotLockedForWrite = mysql.ErrTableNotLockedForWrite
codeErrTableNotLocked = mysql.ErrTableNotLocked
codeErrNonuniqTable = mysql.ErrNonuniqTable
codeErrAccessDenied = mysql.ErrAccessDenied
codeTableLocked = mysql.ErrTableLocked
)
func init() {
schemaMySQLErrCodes := map[terror.ErrCode]uint16{
codeDBDropExists: mysql.ErrDBDropExists,
codeDatabaseNotExists: mysql.ErrBadDB,
codeTableNotExists: mysql.ErrNoSuchTable,
codeColumnNotExists: mysql.ErrBadField,
codeCannotAddForeign: mysql.ErrCannotAddForeign,
codeWrongFkDef: mysql.ErrWrongFkDef,
codeForeignKeyNotExists: mysql.ErrCantDropFieldOrKey,
codeDatabaseExists: mysql.ErrDBCreateExists,
codeTableExists: mysql.ErrTableExists,
codeBadTable: mysql.ErrBadTable,
codeBadUser: mysql.ErrBadUser,
codeColumnExists: mysql.ErrDupFieldName,
codeIndexExists: mysql.ErrDupIndex,
codeMultiplePriKey: mysql.ErrMultiplePriKey,
codeTooManyKeyParts: mysql.ErrTooManyKeyParts,
codeKeyNameDuplicate: mysql.ErrDupKeyName,
codeKeyNotExists: mysql.ErrKeyDoesNotExist,
codeErrTableNotLockedForWrite: mysql.ErrTableNotLockedForWrite,
codeErrTableNotLocked: mysql.ErrTableNotLocked,
codeErrNonuniqTable: mysql.ErrNonuniqTable,
mysql.ErrAccessDenied: mysql.ErrAccessDenied,
codeTableLocked: mysql.ErrTableLocked,
mysql.ErrDBCreateExists: mysql.ErrDBCreateExists,
mysql.ErrDBDropExists: mysql.ErrDBDropExists,
mysql.ErrAccessDenied: mysql.ErrAccessDenied,
mysql.ErrBadDB: mysql.ErrBadDB,
mysql.ErrTableExists: mysql.ErrTableExists,
mysql.ErrBadTable: mysql.ErrBadTable,
mysql.ErrBadField: mysql.ErrBadField,
mysql.ErrDupFieldName: mysql.ErrDupFieldName,
mysql.ErrDupKeyName: mysql.ErrDupKeyName,
mysql.ErrNonuniqTable: mysql.ErrNonuniqTable,
mysql.ErrMultiplePriKey: mysql.ErrMultiplePriKey,
mysql.ErrTooManyKeyParts: mysql.ErrTooManyKeyParts,
mysql.ErrCantDropFieldOrKey: mysql.ErrCantDropFieldOrKey,
mysql.ErrTableNotLockedForWrite: mysql.ErrTableNotLockedForWrite,
mysql.ErrTableNotLocked: mysql.ErrTableNotLocked,
mysql.ErrNoSuchTable: mysql.ErrNoSuchTable,
mysql.ErrKeyDoesNotExist: mysql.ErrKeyDoesNotExist,
mysql.ErrCannotAddForeign: mysql.ErrCannotAddForeign,
mysql.ErrWrongFkDef: mysql.ErrWrongFkDef,
mysql.ErrDupIndex: mysql.ErrDupIndex,
mysql.ErrBadUser: mysql.ErrBadUser,
mysql.ErrUserAlreadyExists: mysql.ErrUserAlreadyExists,
mysql.ErrTableLocked: mysql.ErrTableLocked,
}
terror.ErrClassToMySQLCodes[terror.ClassSchema] = schemaMySQLErrCodes