Skip to content

Commit

Permalink
[parser] parser: implement Restore for CreateUserStmt, AlterUserStmt …
Browse files Browse the repository at this point in the history
…and DropUserStmt (pingcap#197)
  • Loading branch information
exialin authored and tiancaiamao committed Feb 12, 2019
1 parent e82aca8 commit 1c77ade
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 56 deletions.
20 changes: 6 additions & 14 deletions parser/ast/dml.go
Original file line number Diff line number Diff line change
Expand Up @@ -1798,18 +1798,6 @@ func (n *ShowStmt) Restore(ctx *RestoreCtx) error {
}
return nil
}
restoreUserName := func() error {
if n.User.CurrentUser {
ctx.WriteKeyWord("CURRENT_USER")
} else {
ctx.WriteString(n.User.Username)
if n.User.Hostname != "" {
ctx.WritePlain("@")
ctx.WriteString(n.User.Hostname)
}
}
return nil
}

ctx.WriteKeyWord("SHOW ")
switch n.Tp {
Expand All @@ -1831,12 +1819,16 @@ func (n *ShowStmt) Restore(ctx *RestoreCtx) error {
ctx.WriteName(n.DBName)
case ShowCreateUser:
ctx.WriteKeyWord("CREATE USER ")
restoreUserName()
if err := n.User.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore ShowStmt.User")
}
case ShowGrants:
ctx.WriteKeyWord("GRANTS")
if n.User != nil {
ctx.WriteKeyWord(" FOR ")
restoreUserName()
if err := n.User.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore ShowStmt.User")
}
}
case ShowMasterStatus:
ctx.WriteKeyWord("MASTER STATUS")
Expand Down
89 changes: 79 additions & 10 deletions parser/ast/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ type AuthOption struct {
// TODO: support auth_plugin
}

// Restore implements Node interface.
func (n *AuthOption) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("IDENTIFIED BY ")
if n.ByAuthString {
ctx.WriteString(n.AuthString)
} else {
ctx.WriteKeyWord("PASSWORD ")
ctx.WriteString(n.HashString)
}
return nil
}

// TraceStmt is a statement to trace what sql actually does at background.
type TraceStmt struct {
stmtNode
Expand Down Expand Up @@ -559,28 +571,42 @@ type UserSpec struct {
AuthOpt *AuthOption
}

// Restore implements Node interface.
func (n *UserSpec) Restore(ctx *RestoreCtx) error {
if err := n.User.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore UserSpec.User")
}
if n.AuthOpt != nil {
ctx.WritePlain(" ")
if err := n.AuthOpt.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore UserSpec.AuthOpt")
}
}
return nil
}

// SecurityString formats the UserSpec without password information.
func (u *UserSpec) SecurityString() string {
func (n *UserSpec) SecurityString() string {
withPassword := false
if opt := u.AuthOpt; opt != nil {
if opt := n.AuthOpt; opt != nil {
if len(opt.AuthString) > 0 || len(opt.HashString) > 0 {
withPassword = true
}
}
if withPassword {
return fmt.Sprintf("{%s password = ***}", u.User)
return fmt.Sprintf("{%s password = ***}", n.User)
}
return u.User.String()
return n.User.String()
}

// EncodedPassword returns the encoded password (which is the real data mysql.user).
// The boolean value indicates input's password format is legal or not.
func (u *UserSpec) EncodedPassword() (string, bool) {
if u.AuthOpt == nil {
func (n *UserSpec) EncodedPassword() (string, bool) {
if n.AuthOpt == nil {
return "", true
}

opt := u.AuthOpt
opt := n.AuthOpt
if opt.ByAuthString {
return auth.EncodePassword(opt.AuthString), true
}
Expand All @@ -603,7 +629,19 @@ type CreateUserStmt struct {

// Restore implements Node interface.
func (n *CreateUserStmt) Restore(ctx *RestoreCtx) error {
return errors.New("Not implemented")
ctx.WriteKeyWord("CREATE USER ")
if n.IfNotExists {
ctx.WriteKeyWord("IF NOT EXISTS ")
}
for i, v := range n.Specs {
if i != 0 {
ctx.WritePlain(", ")
}
if err := v.Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while restore CreateUserStmt.Specs[%d]", i)
}
}
return nil
}

// Accept implements Node Accept interface.
Expand Down Expand Up @@ -639,7 +677,26 @@ type AlterUserStmt struct {

// Restore implements Node interface.
func (n *AlterUserStmt) Restore(ctx *RestoreCtx) error {
return errors.New("Not implemented")
ctx.WriteKeyWord("ALTER USER ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
if n.CurrentAuth != nil {
ctx.WriteKeyWord("USER")
ctx.WritePlain("() ")
if err := n.CurrentAuth.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore AlterUserStmt.CurrentAuth")
}
}
for i, v := range n.Specs {
if i != 0 {
ctx.WritePlain(", ")
}
if err := v.Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while restore AlterUserStmt.Specs[%d]", i)
}
}
return nil
}

// SecureText implements SensitiveStatement interface.
Expand Down Expand Up @@ -674,7 +731,19 @@ type DropUserStmt struct {

// Restore implements Node interface.
func (n *DropUserStmt) Restore(ctx *RestoreCtx) error {
return errors.New("Not implemented")
ctx.WriteKeyWord("DROP USER ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
for i, v := range n.UserList {
if i != 0 {
ctx.WritePlain(", ")
}
if err := v.Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while restore DropUserStmt.UserList[%d]", i)
}
}
return nil
}

// Accept implements Node Accept interface.
Expand Down
15 changes: 15 additions & 0 deletions parser/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"

"github.com/pingcap/errors"
. "github.com/pingcap/parser/format"
"github.com/pingcap/parser/terror"
)

Expand All @@ -32,6 +33,20 @@ type UserIdentity struct {
AuthHostname string // Match in privs system (i.e. could be a wildcard)
}

// Restore implements Node interface.
func (user *UserIdentity) Restore(ctx *RestoreCtx) error {
if user.CurrentUser {
ctx.WriteKeyWord("CURRENT_USER")
} else {
ctx.WriteName(user.Username)
if user.Hostname != "" {
ctx.WritePlain("@")
ctx.WriteName(user.Hostname)
}
}
return nil
}

// String converts UserIdentity to the format user@host.
func (user *UserIdentity) String() string {
// TODO: Escape username and hostname.
Expand Down
64 changes: 32 additions & 32 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ func (s *testParserSuite) TestDBAStmt(c *C) {
{`SHOW FULL TABLES FROM icar_qa LIKE play_evolutions`, true, "SHOW FULL TABLES IN `icar_qa` LIKE `play_evolutions`"},
{`SHOW FULL TABLES WHERE Table_Type != 'VIEW'`, true, "SHOW FULL TABLES WHERE `Table_Type`!='VIEW'"},
{`SHOW GRANTS`, true, "SHOW GRANTS"},
{`SHOW GRANTS FOR 'test'@'localhost'`, true, "SHOW GRANTS FOR 'test'@'localhost'"},
{`SHOW GRANTS FOR 'test'@'localhost'`, true, "SHOW GRANTS FOR `test`@`localhost`"},
{`SHOW GRANTS FOR current_user()`, true, "SHOW GRANTS FOR CURRENT_USER"},
{`SHOW GRANTS FOR current_user`, true, "SHOW GRANTS FOR CURRENT_USER"},
{`SHOW COLUMNS FROM City;`, true, "SHOW COLUMNS IN `City`"},
Expand Down Expand Up @@ -2058,40 +2058,40 @@ func (s *testParserSuite) TestType(c *C) {
func (s *testParserSuite) TestPrivilege(c *C) {
table := []testCase{
// for create user
{`CREATE USER 'test'`, true, ""},
{`CREATE USER test`, true, ""},
{"CREATE USER `test`", true, ""},
{`CREATE USER 'test'`, true, "CREATE USER `test`@`%`"},
{`CREATE USER test`, true, "CREATE USER `test`@`%`"},
{"CREATE USER `test`", true, "CREATE USER `test`@`%`"},
{"CREATE USER test-user", false, ""},
{"CREATE USER test.user", false, ""},
{"CREATE USER 'test-user'", true, ""},
{"CREATE USER `test-user`", true, ""},
{"CREATE USER 'test-user'", true, "CREATE USER `test-user`@`%`"},
{"CREATE USER `test-user`", true, "CREATE USER `test-user`@`%`"},
{"CREATE USER test.user", false, ""},
{"CREATE USER 'test.user'", true, ""},
{"CREATE USER `test.user`", true, ""},
{"CREATE USER uesr1@localhost", true, ""},
{"CREATE USER `uesr1`@localhost", true, ""},
{"CREATE USER uesr1@`localhost`", true, ""},
{"CREATE USER `uesr1`@`localhost`", true, ""},
{"CREATE USER 'uesr1'@localhost", true, ""},
{"CREATE USER uesr1@'localhost'", true, ""},
{"CREATE USER 'uesr1'@'localhost'", true, ""},
{"CREATE USER 'uesr1'@`localhost`", true, ""},
{"CREATE USER `uesr1`@'localhost'", true, ""},
{"create user 'bug19354014user'@'%' identified WITH mysql_native_password", true, ""},
{"create user 'bug19354014user'@'%' identified WITH mysql_native_password by 'new-password'", true, ""},
{"create user 'bug19354014user'@'%' identified WITH mysql_native_password as 'hashstring'", true, ""},
{`CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, ""},
{`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, ""},
{`CREATE USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true, ""},
{`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true, ""},
{`ALTER USER IF EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, ""},
{`ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, ""},
{`ALTER USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true, ""},
{`ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true, ""},
{`ALTER USER USER() IDENTIFIED BY 'new-password'`, true, ""},
{`ALTER USER IF EXISTS USER() IDENTIFIED BY 'new-password'`, true, ""},
{`DROP USER 'root'@'localhost', 'root1'@'localhost'`, true, ""},
{`DROP USER IF EXISTS 'root'@'localhost'`, true, ""},
{"CREATE USER 'test.user'", true, "CREATE USER `test.user`@`%`"},
{"CREATE USER `test.user`", true, "CREATE USER `test.user`@`%`"},
{"CREATE USER uesr1@localhost", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER `uesr1`@localhost", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER uesr1@`localhost`", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER `uesr1`@`localhost`", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER 'uesr1'@localhost", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER uesr1@'localhost'", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER 'uesr1'@'localhost'", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER 'uesr1'@`localhost`", true, "CREATE USER `uesr1`@`localhost`"},
{"CREATE USER `uesr1`@'localhost'", true, "CREATE USER `uesr1`@`localhost`"},
{"create user 'bug19354014user'@'%' identified WITH mysql_native_password", true, "CREATE USER `bug19354014user`@`%`"},
{"create user 'bug19354014user'@'%' identified WITH mysql_native_password by 'new-password'", true, "CREATE USER `bug19354014user`@`%` IDENTIFIED BY 'new-password'"},
{"create user 'bug19354014user'@'%' identified WITH mysql_native_password as 'hashstring'", true, "CREATE USER `bug19354014user`@`%` IDENTIFIED BY PASSWORD 'hashstring'"},
{`CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, "CREATE USER IF NOT EXISTS `root`@`localhost` IDENTIFIED BY 'new-password'"},
{`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, "CREATE USER `root`@`localhost` IDENTIFIED BY 'new-password'"},
{`CREATE USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true, "CREATE USER `root`@`localhost` IDENTIFIED BY PASSWORD 'hashstring'"},
{`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true, "CREATE USER `root`@`localhost` IDENTIFIED BY 'new-password', `root`@`127.0.0.1` IDENTIFIED BY PASSWORD 'hashstring'"},
{`ALTER USER IF EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, "ALTER USER IF EXISTS `root`@`localhost` IDENTIFIED BY 'new-password'"},
{`ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, "ALTER USER `root`@`localhost` IDENTIFIED BY 'new-password'"},
{`ALTER USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true, "ALTER USER `root`@`localhost` IDENTIFIED BY PASSWORD 'hashstring'"},
{`ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true, "ALTER USER `root`@`localhost` IDENTIFIED BY 'new-password', `root`@`127.0.0.1` IDENTIFIED BY PASSWORD 'hashstring'"},
{`ALTER USER USER() IDENTIFIED BY 'new-password'`, true, "ALTER USER USER() IDENTIFIED BY 'new-password'"},
{`ALTER USER IF EXISTS USER() IDENTIFIED BY 'new-password'`, true, "ALTER USER IF EXISTS USER() IDENTIFIED BY 'new-password'"},
{`DROP USER 'root'@'localhost', 'root1'@'localhost'`, true, "DROP USER `root`@`localhost`, `root1`@`localhost`"},
{`DROP USER IF EXISTS 'root'@'localhost'`, true, "DROP USER IF EXISTS `root`@`localhost`"},

// for grant statement
{"GRANT ALL ON db1.* TO 'jeffrey'@'localhost';", true, ""},
Expand Down

0 comments on commit 1c77ade

Please sign in to comment.